Aspectj advice order - spring

I'm using spring #Transctional with aspectj mode and load time weaving.
My aspect uses a point cut that matches annotation #MyAnnotation
#Aspect
#Configurable
public class MyAspect{
....
#Around("execution(* *(..)) && #annotation(annotation)")
public Object around( ProceedingJoinPoint joinPoint, MyAnnotation annotation ) throws Throwable {
...
}
}
,and is declared in aop.xml:
<aspectj>
<weaver>
<include within="mypackage..*"/>
</weaver>
<aspects>
<aspect name="mypackage.MyAspect" />
</aspects>
</aspectj>
My usage:
#Transactional
#MyAnnotation
private void method() {
...
}
How can I order the aspect invocation order so that the Transactional aspect is called before MyAspect?
I need it to first create a transaction then call my aspect logic inside that transaction.

Solved it by adding #DeclarePrecedence to aspect:
#Aspect
#DeclarePrecedence("org.springframework.transaction.aspectj.*,*")
#Configurable
public class MyAspect
The spring aspect which handles #Transactional is org.springframework.transaction.aspectj.AnnotationTransactionAspect, but to be on the safe side for future renames I used org.springframework.transaction.aspectj.*.

Related

#Autowired not working in spring Integration

In service implementation,with help of #Autowired i am injecting CollectInfo object in serviceImpl but i am getting NullPointerException.
package net.group.cts.service.serviceImpl;
#Service
public class EmployeeImpl implements EmployeeService {
#Autowired
CollectInfo info;
public void processData(){
info.getName();
}
}
package net.group.cts.model;
#Component
public class CollectInfo (){
String name;
public String getName(){
name = name + "Mr.";
return name;}
}
}
Xmlconfig.xml
<context:annotation-config/>
<context:component-scan base-package="net.group.cts"/>
<bean id="info" class="net.group.emp.model.CollectInfo "/>
You cannot inject a bean in a class if this class is not a Spring bean.
EmployeeImpl is not annotated with any Spring bean stereotype such as #Component or #Service.
Add one of them on EmployeeImpl and ensure that the two classes are located inside the package scanned by Spring <context:component-scan base-package="net.group.emp.service"/>
and it should be ok.
Besides, both annotating a bean with #Component :
#Component
public class CollectInfo (){...}
and configuring it in the Spring xml configuration :
<bean id="info" class="net.group.emp.model.CollectInfo "/>
is redundant. It will finally create two beans : one name collectInfo and another named info.
I advise you to favor annotation over xml configuration as it is possible (it is the very most of cases).

#Autowired dependencies are null in compile time weaving of #Aspect class [duplicate]

I have the following spring configuration:
<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>
<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>
<aop:aspectj-autoproxy/>
Then I have an aspect:
#Aspect
public class SyncLoggingAspect {
#Autowired
private SimpleEmailSender simpleEmailSender
#AfterReturning(value="execution(* uk.co.mysite.datasync.polling.Poller+.doPoll())", returning="pusher")
public void afterPoll(Pusher pusher) {
simpleEmailSender.send(new PusherEmail(pusher));
}
}
This aspect works (I can hit a breakpoint on afterPoll) but simpleEmailSender is null. Unfortunately I cannot find clear documentation on why this is. (For the record, my simpleEmailSender bean exists and is correctly wired into other classes) The following things confuse me:
Is context:component-scan supposed to be picking up #Aspect? If it is then surely it would be a spring managed bean, thus autowired should work?
If context:component-scan isn't for creating aspects, how is my aspect being created? I thought aop:aspectj-autoproxy just creates a beanPostProcessor to proxy my #Aspect class? How would it do this if it isn't a spring managed bean?
Obviously you can tell I don't have an understanding of how things should be working from the ground up.
The aspect is a singleton object and is created outside the Spring container. A solution with XML configuration is to use Spring's factory method to retrieve the aspect.
<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect"
factory-method="aspectOf" />
With this configuration the aspect will be treated as any other Spring bean and the autowiring will work as normal.
You have to use the factory-method also on Enum objects and other objects without a constructor or objects that are created outside the Spring container.
For Spring Boot to use #Autowired with AspectJ I have found the following method.
In configuration class add your aspect:
#Configuration
#ComponentScan("com.kirillch.eqrul")
public class AspectConfig {
#Bean
public EmailAspect theAspect() {
EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
return aspect;
}
}
Then you can successfully autowire your services in your aspect class:
#Aspect
public class EmailAspect {
#Autowired
EmailService emailService;
Another option is to add #Configurable to your aspect class instead of messing around with XML.
Configuring #Autowired with java config only (so no XML based configuration) requires a bit of extra work than just adding #Configuration to the class, as it also needs the aspectOf method.
What worked for me was creating a new class:
#Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
And then use that in you aspect in conjunction with using #DependsOn #Configured and #Autowired:
#DependsOn("springApplicationContextHolder")
#Configuration
#Aspect
public class SomeAspect {
#Autowired
private SomeBean someBean;
public static SomeAspect aspectOf() {
return SpringApplicationContextHolder.getApplicationContext().getBean(SomeAspect.class);
}
The #DependsOn is needed because spring can't determine the dependency because the bean is used staticly.
I dont have 50 rep to comment on a question so here is another answer relating to #
Jitendra Vispute answer.
The official Spring doc mentions:
You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the #Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate #Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).Source: Spring '4.1.7.Release' documentation.
This would mean that adding a #Component annotation and adding the #ComponentScan on your Configuration would make #Jitendra Vispute's example work. For the spring boot aop sample it worked, though I did not mess around with context refreshing.Spring boot aop sample:
Application:
package sample.aop;
#SpringBootApplication
public class SampleAopApplication implements CommandLineRunner {
// Simple example shows how an application can spy on itself with AOP
#Autowired
private HelloWorldService helloWorldService;
#Override
public void run(String... args) {
System.out.println(this.helloWorldService.getHelloMessage());
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleAopApplication.class, args);
}
}
The application should also run as plain Spring Framework application with the following annotations instead of #SpringBootApplication:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
and an AnnotationConfigApplicationContext instead of SpringApplication.
Service:
package sample.aop.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class HelloWorldService {
#Value("${name:World}")
private String name;
public String getHelloMessage() {
return "Hello " + this.name;
}
}
Monitor Aspect:
package sample.aop.monitor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class ServiceMonitor {
#AfterReturning("execution(* sample..*Service.*(..))")
public void logServiceAccess(JoinPoint joinPoint) {
System.out.println("Completed: " + joinPoint);
}
}
This blog post explains it really well. Due to the fact that aspect singleton is created outside spring container you'd need to use factory-method=”aspectOf” that is only available after it is woven in by AspectJ ( not Spring AOP ) :
Notice factory-method=”aspectOf” that tells Spring to use a real
AspectJ ( not Spring AOP ) aspect to create this bean. So that after
the aspect is woven in it has an
“aspectOf” method.
So that :
No matching factory method found: factory method 'aspectOf()' - That
would mean that the aspect was not woven by AspectJ weaver.
From my experience with spring 3.1, if I don't use #Autowired but traditional setter for dependency injection, it gets injected and works as expected without aspectJ weaver. Although I'm encountering problems with the aspect being singleton... It results in 'perthis' instantiation model.
.
Add #Component to aspect class and your dependencies should get injected automatically.
and add context:component-scan for package where your aspect is in spring context file.
#Component
#Aspect
public class SomeAspect {
/* following dependency should get injected */
#Autowired
SomeTask someTask;
/* rest of code */
}
Use compile time weaving, see for plugin example at: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml
The following combination of annotation and Spring config works for me thanks to notes above by Tobias/Willie/Eric:
Class:
package com.abc
#Configurable
#Aspect
public class MyAspect {
#Autowired
protected SomeType someAutoWiredField;
}
XML:
<context:spring-configured />
<context:component-scan base-package="com.abc" />
#Configurable(autowire = Autowire.BY_TYPE)
Add this annotation to your Aspectj class. Then it will be handled by Spring IOC.
For Spring Boot using #Autowired in #Aspect,
my way is using spring.factories configuration file
create a file named spring.factories in src/main/resources
the file content is as following
org.springframework.boot.autoconfigure.EnableAutoConfiguration=pack.age.to.YourAspect,pack.age.to.YourDAO

Performance method audit with spring, aspectj and annotation based

I have a question about how to do an time performance audit over a method using annotations, aspectj and spring
basically I have:
public class MyClass{
#TimeAudit
public myMethod(){
//do something
}
}
i want to just log(or just print it in console) somewhere the time spent for that method to be executed. My problem is how an aspect will intercept that annotation and after that count the time that method spent.
How i can do that?
to clarify a little bit my question:
I have the annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface TimeAudit {
}
i have my aspect:
#Aspect
#Component
public class PerformanceTimeExecutionAudit {
#Around("execution(* *(..)) && #annotation(timeAudit)")
public Object doLogTime(final ProceedingJoinPoint pjp, TimeAudit timeAudit) throws Throwable {
System.out.println("Start time..."+System.currentTimeMillis());
Object output = pjp.proceed();
System.out.println("End time..."+System.currentTimeMillis());
return output;
}
}
on other class:
#Repository
public class MyClass{
#Override
#TimeAudit
public void myMethod(){
//do something
}
}
but the aspect is not triggered for that method were i put #TimeAudit.
What i do wrong?
To summarise a short tutorial how to create an aspect in conjunction with Annotation to be useful for newcomers in this area.
you need the library dependencies:
aspectjrt
aspectjweaver
spring-aop
along with others spring dependencies like spring context etc.
2 Create your Annotation example:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface TimeAudit {
//put here whatever fields you need
}
3 Create your aspect, example:
#Aspect
#Component
public class PerformanceTimeExecutionAudit {
#Around("execution(* *(..)) && #annotation(TimeAudit)")
public Object doLogTime(final ProceedingJoinPoint pjp, TimeAudit timeAudit) throws Throwable {
System.out.println("Start time..."+System.currentTimeMillis());
Object output = pjp.proceed();
//this is with #Around, you can use in your asspect all others annotations like #Before, #After etc. this depends on your logic behavior.
System.out.println("End time..."+System.currentTimeMillis());
return output;
}
}
4 On your your methods use your annotation like this - A little observations is that you can create the Annotation to behave as you want.
#Repository
public class MyClass{
#Override
#TimeAudit
public void myMethod(){
//do something
}
}
//- this #TimeAudit can contain params, this depends on your Annotation logic creation
be sure your spring context is scanning your packages where you have the Aspect, and also the package where you have the class annotated. Or you can declare them as beans in spring context configuration.
Be sure that you enabled the AOP. You need something like this in your spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="........
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=".........
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
That's it.
I hope it will be useful for someone.

#Transactional AspectJ Advice

I added my custom #Around advice to bean's method. Bean is transactional. How can I make by advice to run within the transaction?
I use AspectJ to add advices.
Advice code:
#Aspect
#Order(200)
public class MyAdvice {
#Around
public Object wrap(final ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
// some processing that requires a transaction
return ret;
}
}
Bean code:
public class MyBean {
// method is wrapped by MyAdvice.wrap
#Transactional
public Object someBusinessMethod() {
// ...
}
}
Spring configuration:
<tx:annotation-driven transaction-manager="transactionManager" order="100" mode="proxy" />
<aop:aspectj-autoproxy />
I need the MyAdvice.wrap to run within the same transaction as MyBean.someBusinessMethod.

Spring Boot AOP load time weaving

Not sure what is going wrong, but AOP just doesn't seem to be working in my setup with spring boot (v1.1.6).
#Configuration
#ComponentScan
#EnableJpaRepositories
#EnableTransactionManagement
#EnableAutoConfiguration
#EnableCaching
#EnableLoadTimeWeaving
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And in the aspect class
#Aspect
public class MyAspect {
#AfterReturning(pointcut = "execution(private * com.myapp.service.MyService.test(..)) && args(str1,str2)", argNames = "str1,str2")
public void advice(String str1, String str2) throws IOException {
System.out.println("Advising after returning");
}
}
In the service class that needs the advice
#Service
public class MyService {
public void test(String str1, String str2) throws IOException {
System.out.println("Test method in service");
//rest of the implementation
}
}
I also have a META-INF/aop.xml like so
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="com.myapp.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="com.myapp.aspect.MyAspect"/>
</aspects>
</aspectj>
When I run the application with -javaagent:path/to/spring-instrument-4.1.0.RELEASE.jar
I get this message on the console
2014-09-05 08:42:12.500 INFO 65053 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[AppClassLoader#58644d46] warning javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified
2014-09-05 08:42:13.114 INFO 65053 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2014-09-05 08:42:13.156 INFO 65053 --- [ main] o.s.b.a.e.jmx.EndpointMBeanExporter : Registering beans for JMX exposure on startup
[AppClassLoader#58644d46] error can't determine implemented interfaces of missing type org.springframework.security.config.http.SessionCreationPolicy
when weaving type org.springframework.boot.actuate.autoconfigure.ManagementServerProperties$Security
when weaving classes
when weaving
[Xlint:cantFindType]
[AppClassLoader#58644d46] error can't determine implemented interfaces of missing type org.springframework.security.config.http.SessionCreationPolicy
when weaving type org.springframework.boot.actuate.autoconfigure.ManagementServerProperties$Security
when weaving classes
when weaving
[Xlint:cantFindType]
Nothing happens with the advice though. It won't fire.
Am I doing something wrong?
In order to advise private methods you need to use a privileged aspect:
public privileged aspect MyAspect {
// ...
}
But the AspectJ documentation says:
Limitations: Privileged aspects are not supported by the annotation style.
So please use native syntax, not #AspectJ style. Before you do that, though, test if non-privileged, annotation-style aspects work as expected with public methods in order to exclude other reasons for your aspects being woven.
I had the same problem. In my case I had to annotate my aspect class with the annotation #Component.
#Aspect
#Component
public class MyAspect {
...
}
The following link has a spring boot AOP example that helped me
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-aop
Add below changes to your code and it should work. Do not need to create aop.xml. These changes will add the aspect to container and also weave it.
Read -- Enable Spring AOP or AspectJ
#Configuration
#ComponentScan
#EnableJpaRepositories
#EnableTransactionManagement
#EnableAutoConfiguration
#EnableCaching
#EnableAspectJAutoProxy -- Use this instead of #EnableLoadTimeWeaving
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#Aspect
#Component/#Configurable -- Both of them work
public class MyAspect {
...
}

Resources