Trying to use both AspectJ and @Configurable with a Spring application.
- If I load Spring with a
@Componentannotation on a class, the AspectJ wrapper works and wraps all targeted methods AND the@Autowiredannotation causes dependencies to be injected. But the class cannot be instantiated at runtime with thenewkeyword and have dependencies injected. - If I load a
@Configurableclass without the AspectJ bean, all dependencies are injected correctly onnewbut none of the methods are proxied through AspectJ.
How can I do both?
Here's my code. Configuration:
@Configuration @ComponentScan(basePackages="com.example") @EnableSpringConfigured @EnableAspectJAutoProxy @EnableLoadTimeWeaving public class TestCoreConfig { @Bean public SecurityAspect generateSecurityAspect(){ return new SecurityAspect(); } @Bean public SampleSecuredClass createSampleClass(){ return new SampleSecuredClass(); } } Aspect:
@Aspect public class SecurityAspect { @Pointcut("execution(public * *(..))") public void publicMethod() {} @Around("publicMethod()") public boolean test (ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Here!"); joinPoint.proceed(); return true; } } SampleClass:
//@Configurable @Component public class SampleSecuredClass { @Autowired public SecurityService securityService; public boolean hasSecurityService(){ return securityService != null; } public boolean returnFalse(){ return false; } } And the unit test:
@ContextConfiguration(classes={TestCoreConfig.class}) @RunWith(SpringJUnit4ClassRunner.class) public class SecurityAspectComponentTest { @Autowired private SampleSecuredClass sampleSecuredClass; @Test public void testSecurityRoles(){ //SampleSecuredClass sampleSecuredClass = new SampleSecuredClass(); assertTrue("We need to ensure the the @Configurable annotation injected the services correctly", sampleSecuredClass.hasSecurityService()); assertTrue("We need to ensure the the method has been overwritten", sampleSecuredClass.returnFalse()); } } - If I get rid of the beans in the
TestCoreConfigand create an instance ofSampleSecuredClassin the test withnew, and change its annotation to@Configurablethen the service is injected, but the aspect is not applied. - If I run as is here (by injecting the
SampleSecuredClassas a bean), then the aspect works and the service is injected, but then all objects have to be created on framework start. I would like to use the@Configurableannotation. - If I use both the
@Configurableannotation and the Aspect together then I get aillegal type in constant poolerror and the context does not start.
Other pieces of information.
I have tried a few different java agents--both spring instrumentation and aspectjwrapper. no change.
If I include an aop.xml file, then the aspect works but not the @Configurable.
1 Answer
This seems one of those deep dives sessions into the docs waiting to happen :)
First of all I'd enable debug logging for org.springframework because this will definitely provide some meaningful insight into what and when Spring does...
That being said I believe that your problem lies somewhere in the mist of spring's context lifecycles so I'd check out the docs carefully especially around
Manually specifying that the bean depends on the configuration aspect
depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"...or the note around
@Configurable(preConstruction=true)
If you want the dependencies to be injected before the constructor bodies execute
- ...or
@Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true)
Finally you can enable Spring dependency checking for the object references in the newly created and configured object by using the dependencyCheck attribute.
Read the docs carefully, see if and how these hits apply and please let us know the solution you find. It should definitely present itself as a very interesting read.