Configuring AspectJ aspects using Spring IoC with JavaConfig? - java

According to Spring's Documentation Configuring AspectJ aspects using Spring IoC in order to configure an aspect for Spring IOC, the following has to be added to the xml configuration:
<bean id="profiler" class="com.xyz.profiler.Profiler"
factory-method="aspectOf">
<property name="profilingStrategy" ref="jamonProfilingStrategy"/>
</bean>
As suggested by #SotiriosDelimanolis, rewriting this as the following in JavaConfig should to work:
#Bean
public com.xyz.profiler.Profiler profiler() {
com.xyz.profiler.Profiler profiler = com.xyz.profiler.Profiler.aspectOf();
profiler.setProfilingStrategy(jamonProfilingStrategy()); // assuming you have a corresponding #Bean method for that bean
return profiler;
}
However, this only seems to work if the Profiler aspect is written in native aspectj .aj syntax. If it is written in Java and annotated with #Aspect, I get the following error message:
The method aspectOf() is undefined for the type Profiler
Is there an equivalent way of writing this using JavaConfig for aspects written with #AspectJ syntax?

Turns out that there is an org.aspectj.lang.Aspects class to provide for specifically this purpose. It appears that the aspectOf() method is added by the LTW which is why it works fine in XML configuration, but not at compile time.
To get around this limitation, org.aspectj.lang.Aspects provides a aspectOf() method:
#Bean
public com.xyz.profiler.Profiler profiler() {
com.xyz.profiler.Profiler profiler = Aspects.aspectOf(com.xyz.profiler.Profiler.class);
profiler.setProfilingStrategy(jamonProfilingStrategy()); // assuming you have a corresponding #Bean method for that bean
return profiler;
}
Hope this helps someone else in the future.

Is there an equivalent way of writing this using JavaConfig?
Almost always.
#Bean
public com.xyz.profiler.Profiler profiler() {
com.xyz.profiler.Profiler profiler = com.xyz.profiler.Profiler.aspectOf();
profiler.setProfilingStrategy(jamonProfilingStrategy()); // assuming you have a corresponding #Bean method for that bean
return profiler;
}
The factory-method is explained in the documentation in Instantiation with a static factory method.

Related

How to use Spring #Component annotation with AspectJ compiler

I excluded part of my project for easier reproduce problem: GitHub repo.
When I compile it by Javac everything works as expected. I see logging in console when I open URLs /user/ and /user/2/:
Access: execution(List ru.krivochenko.demo.user.UserController.getAll())
Access: execution(User ru.krivochenko.demo.user.UserController.getOne(Integer))
But I wanna use AspectJ compiler. When I switch to it, error occurs:
java.lang.NoSuchMethodError: ru.krivochenko.demo.logging.LoggingAspect: method <init>()V not found
As I understood it happens because there is not no-args constructor in LoggingAspect. If I add it, I get another error, because logger is not injected:
java.lang.NullPointerException: null
at ru.krivochenko.demo.logging.LoggingAspect.beforeGettingUsers(LoggingAspect.java:28) ~[classes/:na]
So, how we can see, AspectJ ignores Autowired constructor with args.
In branch via-setter of my repo I implemented another solution. I removed #Component annotation of LoggingAspect and replaced constructor injection to setter injection. In DemoApplication.java I added #Bean configuration of LoggingAspect. It works fine, but in some situations it requires getting dependencies from application context. What is the best practice to resolve it?
Thanks for help.
Spring Aspects and compile time weaving don't automatically integrate. This is primary because aspectj and spring are fairly separate and I suspect Spring's recommended approach is not to use compile time weaving.
So thus by default Aspects are not spring magic and we need to add a little bit of plumbing to ensure they are.
In this regard, it is important to note that Aspects are not spring managed (they are managed by aspectj so we need to add something to ensure they are).
Thus the reason why you need a parameterless constructor on your aspect (so must use field injection).
Traditionally I have had to add the following piece of xml to my xml config files:
<bean id="securityAspect" class="com.<skip>.security.AuthorizationAspect"
factory-method="aspectOf" autowire="byType" />
So this works because the AspectJ compiler adds the static method aspectOf to the aspects and this method is available for acquiring the instance of the Aspect that aspectj creates (and uses).
This method is obviously not available in the source so we can't just add to our application class (DemoApplication):
#Bean
public LoggingAspect loggingAspect() {
return LoggingAspect.aspectOf();
}
Then what to do? My next option was to write some reflective code to call this method then having looked at this very helpful example that demonstrates exactly what you need - The Aspects class from AspectJ has a utilty method that does this work for us, so adding the following to our DemoApplication we have success:
#Bean
public LoggingAspect loggingAspect() {
return Aspects.aspectOf(LoggingAspect.class);
}
Btw, remove the #Component from the LoggingAspect as that will mean both Aspectj and Spring create an instance of the class...
Btw, I'd also suggest you add the following to your test class to demonstrate the problem in a test:
#Autowired
private UserController controller;
#Test
public void contextLoads() {
controller.getAll();
controller.getOne(1);
}
Btw, other suggestions to address this problem used #Configurable. I suspect this might work but you'll need to make sure you include the spring aspects java in your aspectj compile time config and I suspect it may still not work as I'm not sure the Spring context will be ready in time. i.e. if the Aspect is created before the spring context then #Configurable won't work as the beans to be injected will not yet be created.
Your approach to configure the aspect via setter injection looks valid to me. For more information about how to use AspectJ in combination with Spring check out the corresponding chapter in the Spring manual, specifically the description about how to configure AspectJ aspects by Spring IoC. It is mostly explained in the context of LTW, but it should work pretty much the same for CTW.

AspectJ, SpringAOP, Aspect runs twice

My aspect runs twice and I don't see a reason why. Maybe someone could point me on my mistake?
Here is a code:
Creating annotation for pointcut
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface CustodianMetrics {
String metricId();
}
Creating an aspect
#Aspect
#Component("custodianMetricsAspect")
public class CustodianMetricsAspect {
private final MonitoringService monitoringService;
#Autowired
public CustodianMetricsAspect(MonitoringService monitoringService) {
this.monitoringService = monitoringService;
}
#After("#annotation(custodianMetricsAnnotation)")
public void count(CustodianMetrics custodianMetricsAnnotation) {
Counter metric = monitoringService.metric(custodianMetricsAnnotation.metricId(), Counter.class);
metric.inc();
}
}
Configuring xml for spring
<aop:aspectj-autoproxy>
<aop:include name="path"/>
</aop:aspectj-autoproxy>
<aop:config>
<aop:aspect id="custodianMetricsAspect" ref="custodianMetricsAspect">
<aop:after method="count"
pointcut="#annotation(custodianMetricsAnnotation)"/>
</aop:aspect>
</aop:config>
I tried to change poitcut on this
#After("#annotation(custodianMetricsAnnotation) && execution(* *(..))")
But the same result - aspect runs twice. Any suggestions?
It happens because you have configured the aspect twice - both Spring XML configuration and the #Aspect annotation.
Read the note in section 8.1.2 Spring AOP capabilities and goals of Spring framework documentation, it states the following:
One such choice that is relevant to this chapter is that of which AOP framework (and which AOP style) to choose. You have the choice of AspectJ and/or Spring AOP, and you also have the choice of either the #AspectJ annotation-style approach or the Spring XML configuration-style approach.
In this case, based on my personal experience, I highly recommend you to stick with the annotations. However, it depends on your personal taste. You may find 8.4 Choosing which AOP declaration style to use relevant.
Edit:
If you choose the annotation-based configuration, don't forget to create a Java configuration class instead of deleted <aop:aspectj-autoproxy>... line.
#Configuration
#EnableAspectJAutoProxy
public class AspectJAutoProxyConfiguration { }

Is there anyway to get "Effective Spring Config" from all spring beans annotations?

I liked annotations used for bean declaration etc. But now we have so many beans with order (#Depends). It is tough to maintain or look at a glance the configuration.
Is there any tool that provides "Effective Spring Config" information based on all your bean annotations?
Answer: you should not be using that many #DependsOn annotations.
From the javadoc:
Used infrequently in cases where a bean
does not explicitly depend on another through properties or
constructor arguments, but rather depends on the side effects of
another bean's initialization.
You can just do this:
#Configuration
public class MyConfig {
#Bean
public MovieClient movieClient(RestOperations rest) {
return new MovieClientImpl(rest);
}
#Bean
public RestOperations restOps() {
return new RestTemplate();
}
}
In this example, the RestOperations bean will be instantiaded before the MovieClient bean, just because the movieClient bean asks for it in the constructor. You don't need any #DependsOn annotion in cases like this one.
Edit: as OP commented, there is still the issue of showing the "Effective Spring Config".
I do not think there is any tool for that, because your dependencies may change at runtime (because of AutoConfiguration, #Conditional annotations, profiles, other?).
If you need to know your "Effective Spring Config" (i.e. "what beans are present at runtime"), you can do this:
ConfigurableApplicationContest context;
context = SpringApplication.run(Application.class, finalArgs);
// Print all the beans:
System.out.println(context.getBeanDefinitionNames());
However, if you meant how can you view and navigate all the configuration, you can organize your beans in different #Configuration files, pick them up using #ComponentScan, and navigate them using the Spring IDE pluguin for Eclipse, like this:

Pointcut targeting a third party JAR class is not triggered

As a temporary fix of the bug https://github.com/spring-projects/spring-hateoas/issues/220, I would like modify the return value of org.springframework.hateoas.core.AnnotationMappingDiscoverer.getMapping methods so that I can resolve placeholders manually. Here is the aspect I tried:
<aop:aspectj-autoproxy />
#Component
#Aspect
public class AnnotationMappingDiscovererFix {
#Around("execution(* org.springframework.hateoas.core.AnnotationMappingDiscoverer.getMapping(..))")
public Object resolvePlaceholders(ProceedingJoinPoint joinPoint) throws Throwable {
Object mapping = joinPoint.proceed();
// resolve placeholders manually...
return mapping;
}
}
But this pointcut gets never triggered, any idea why?
With proxy-based Spring AOP you can only target Spring beans/components. I am not a Spring user, so I do not know for sure, but I do not think that you can actually intercept Spring framework classes via its own AOP framework due to "hen vs. egg" bootstrapping problems.
But if you use full AspectJ via load-time weaving (LTW), you should be able to achieve what you want because the AspectJ weaving agent (aspectjweaver.jar) is loaded before the Spring classes and thus can modify them during classloading phase. The Spring documentation explains how to use AspectJ in connection with Spring.

Annotation equivalent of <tx:jta-transaction-manager/> for Java EE environments

How can I achieve something similar to this:
<jee:jndi-lookup id="datasSource"
jndi-name="jdbc/dataSourceName" expected-type="javax.sql.DataSource" />
<tx:jta-transaction-manager/>
Using annotations?
#Configuration
#EnableTransactionManagement
public class AppConfig {
#Bean
public DataSource dataSource() {
// What goes here?
}
#Bean
public PlatformTransactionManager txManager() {
// What goes here?
}
}
I've seen a lot of examples with DataSourceTransactionManager and BasicDataSource, but I couldn't find a equivalent annotation driven configuration (that finds the container UserTransaction, etc).
The only way I am aware of is to replicate the behavior of namespace parsers of these custom namespaces.
So, <jee:jndi-lookup> is handled by org.springframework.ejb.config.JndiLookupBeanDefinitionParser and ultimate creates a bean which is an instance of JndiObjectFactoryBean with the passed in attributes.
Similarly, <tx:jta-transaction-manager/> is handled by org.springframework.transaction.config.JtaTransactionManagerBeanDefinitionParser and based on the runtime environment, returns a specific instance of class.
A neat feature of Spring 4 that you can use is #Conditional(reference here). With #Conditional and using a Spring-Boot Conditional implementation called ConditionalOnClass(reference here), you can replicate the behavior of <tx... something like this:
#Configuration
#ConditionalOnClass(name="weblogic.transaction.UserTransaction")
public class WebLogicTxMgrConfig {
#Bean
public JtaTransactionManager txManager() {
return new WebLogicJtaTransactionManager();
}
}
I know this is not a complete answer, but hopefully should help you create the relevant configuration.

Categories