Search code examples
springspring-bootloggingspring-aoppointcut

How to pass base package as a variable inside pointcut expression in Spring AOP?


I am creating a java library for logging purpose so that if any application uses my library then spring AOP's advices are applied to each method of the application. But in my library, I don't know the base package of the applications that will be using it. So, the applications should specify their base package in the application.properties file and my library will use it and put it in my pointcut as a variable. But seems like pointcut expressions only accepts contants inside it.

I don't want to go for annotation based approach.

@Component
@Aspect
@Slf4j
public class LoggingAop {

    @Value("${base.package}")
    String basePackage;

    @Pointcut("within("+basePackage+"..*)") //error
    public void logAllMethods()
    {

    }
}

Solution

  • Answers for the following questions explains why this is not possible with annotation based Spring AOP configuration

    Spring boot supports xml based configurations and the requirement can be achieved as follows.

    Assuming we have to intercept all the method calls within base package com.app.service

    Have an entry in resources/application.properties.

    base.package=com.app.service
    

    An Aspect to log method calls within the base package can be as follows

    package com.app.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    public class LogAspect {
    
        Logger log = LoggerFactory.getLogger(LogAspect.class);
    
        public Object logAllMethods(ProceedingJoinPoint pjp) throws Throwable {
            log.info("Log before method call");
            try {
                return pjp.proceed();
            }finally {
                log.info("Log after method call");
            }
        }
    }
    

    The aop configuration can be defined as follows .

    File : resources/aop-application-context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="logAspect" class="com.app.aspect.LogAspect"></bean>  
    
    <aop:config>  
      <aop:aspect id="logallaspect" ref="logAspect" >  
         <!-- @Around -->  
         <aop:pointcut id="logAllMethodsAround" expression="within(${base.package}..*)" />  
         <aop:around method="logAllMethods" pointcut-ref="logAllMethodsAround" />  
      </aop:aspect>  
    </aop:config>
    
    </beans>
    

    Do note that the pointcut expression is constructed with the application.properties entry.

    Remember to load the aop-application-context.xml as follows

    @SpringBootApplication
    @ImportResource("classpath:aop-application-context.xml")
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
    }
    

    The above code will advice all the interceptable Spring bean method calls within the defined base package and logs them .

    Hope this helps.