Below is my custom annotation SkipForTestProfile which I created to skip execution for "it" profile but the SkipForTestProfileAspect code is not execuuted, i appreciate if someone can help me fix the Aspect to execute around the annotation @SkipForTestProfile
package com.mp.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipForTestProfile {
}
Below is the aspect
package com.mp.aspect;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import com.mp.annotations.SkipForTestProfile;
@Aspect
@Component
@Order(1) // Define the order of aspect execution
public class SkipForTestProfileAspect {
@Autowired
private Environment environment;
@Around("@annotation(skipForTestProfile)")
public Object skipMethodForTestProfile(ProceedingJoinPoint joinPoint, SkipForTestProfile skipForTestProfile) throws Throwable {
if(isTestProfile()){
return null;
} else{
return joinPoint.proceed();
}
}
private boolean isTestProfile() {
return Arrays.stream(environment.getActiveProfiles()).anyMatch(s -> s.equals("it"));
}
}
Below is my custom annotation usage
package com.mp.healthIndicator;
@Component
@Slf4j
@Profile("!it")// this is not working in my case hence created custom annotation
public class HeartBeat{
@PostConstruct
@SkipForTestProfile
protected void init(){
//do health check
}
}
With Spring AOP it is impossible to intercept a bean lifecycle method with an aspect. In order to achieve that, you would have to explicitly call the method on the bean instance, which is not what you want, because Spring does that for you internally. When debugging, you will also see that
HeartBeat's lifecycle method has long since run before the aspect becomes active. You could markHeartBeatas@Lazy, then the aspect bean is wired first, but still that does not mean you can intercept the post-construct method with Spring AOP.Like I commented before, I see no reason why
@Profilewould not work. For me, it works beautifully. Chances are, that your Spring config needs fixing. You still did not provide any reproducer for your problem.If you wish to intercept the post-construct method with an aspect, you need a more powerful AOP tool than Spring AOP, namely native AspectJ. I tried with load-time weaving, and it works, if configured correctly. The code looks like this:
Please note that you need
@Lazy, otherwise you cannot inject theEnvironmentinto the native aspect on time beforeHeartBeat.init()executes.Without
@Lazy, you have to parse the system propertyspring.profiles.activemanually. That is also possible.Please note that a native AspectJ aspect should not carry any
@Componentannotation, because it is not a Spring component. You do, however, need@Configurable(fromspring-aspects) to be able to inject the Spring environment.Again, that is unnecessary, if you parse the system property manually.
In this driver application, you see that we need
@EnableLoadTimeWeavingrather than@EnableAspectJAutoProxyfor native load-time weaving. We also need@EnableSpringConfiguredin order to auto-wire a Spring bean (the environment) into a non-Spring component (the aspect).We also explicitly instantiate a
HeartBeatbean in order to see the effect of the aspect.Now start the application with JVM parameters (on a single line)
to see log output like
Without the active
itprofile, it says:Is that really worth the effort? Would it not be better to get
@Profileand Spring AOP working?Update: If you want to work without
@EnableSpringConfigured,@Configurableand@Lazy, simply instantiate aStandardEnvironmentby yourself inside the aspect, and the sitution is simplified as follows:In this configuration, it is also no longer necessary to instantiate the
HeartBeatbean in the application starter in order to see the aspect log, because there is no@Lazybean instantiation anymore. Everything works automatically during application start.