using Spring @Profile in @Aspect

2019-06-18 21:00发布

So what i want is to apply an specific Spring Aspect to my classes when an profile is active, but i can't find a solution, i try the way proposed in http://city81.blogspot.com/2012/05/using-spring-profile-with.html but is quite old and don't work in my case, i have a Spring Started project for testing and i do the following based on the link:

configuring the Application:

@Configuration
@ComponentScan(basePackages= {
        "demo",
        "demo.aspect"
})
@EnableAutoConfiguration(exclude=AopAutoConfiguration.class)
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class Application {

    @Bean
    @Profile("asdasd") //testing profile to bean level
    public TestAspect testAspect() { //this allow @autowired in my aspect
        TestAspect aspect = Aspects.aspectOf(TestAspect.class);
        return aspect;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

My Aspect:

//TESTING IN ALL THIS WAYS BUT NOTHING
//@Component
//@Profile("asdasd")
@Configurable
//@Configuration
@Aspect
public class TestAspect{
    public static final Logger LOGGER = LogManager.getLogger(testControllerEX.class);

    @Autowired
    private testService testService;

    public TestAspect() {
        LOGGER.info("TEST ASPECT INITIALIZED");
    }

    /*@Before("execution(* demo.testControllerEX.test(*)) && args(param)")
    public void beforeSampleMethod(Object param) {
        LOGGER.info("ASPECT" + param.getClass());
    }*/

    @Before("execution(demo.testControllerEX.new())")
    public void constructor(JoinPoint point) {
        LOGGER.info("ASPECT CONSTRUCTOR" + point.getThis().getClass().getAnnotation(Controller.class));
        LOGGER.info("SERVICE" + testService);
    }

    @Around("execution(* demo.testControllerEX.testPrevent(*)) && args(param)")
    public String prevent(ProceedingJoinPoint point, String param) throws Throwable{
        //LOGGER.info("ASPECT AROUND" + param);
        LOGGER.info("ASPECT AROUND " + testService);
        String result = (String)point.proceed();
        return result;
    }

    /*@DeclareParents(value="(demo.testControllerEX)",defaultImpl=testControllersssImpl.class)
    private ITestControllerEX itestControllerEX;*/
}

Finally i'm try to apply my aspect to the constructor of a controller, it works but i need to applying when a profile is active, and another bug i find is that my testService is initialized after the constructor pointcut so it is null, but in the method testPrevent works obviously the service is initialized before, i can accept other form that accomplished what i want

EDIT

i got that my testService is loaded befome my constructor pointcut but remains null:

@Configuration
    @ComponentScan(basePackages= {
            "demo",
            "demo.aspect"
    })
    @EnableAutoConfiguration(exclude=AopAutoConfiguration.class)
    @EnableAspectJAutoProxy(proxyTargetClass=true)
    public class Application {

    @Autowired
    private testService testService;
    ...

1条回答
手持菜刀,她持情操
2楼-- · 2019-06-18 21:19

Unfortunately for you it's not going to be possible to achieve what you want to do. With pure Spring AOP there is no way to apply advice to constructor call so your only way is to use LTW (Load Time Weaving) with AspectJ.

Link to Spring AOP reference (Spring AOP capabilities and goals)

Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans).

You may have already read about LTW to intercept your constructor call but your Aspect will not be a Spring Bean so you won't be able to inject your TestService. In the same way you are trying to set a Profile to a non Spring Bean (as your advice is not going to be managed by Spring) so you won't be able make it active depending on you active spring profiles.

By the way, using profiles in conjunction with Spring AOP is totally supported as long as you stay with spring managed aspects.

It would be interesting to know more about what you want to do, may be what you are trying to do is doable without using constructor call interceptor !

查看更多
登录 后发表回答