Aspect never gets called - java

My goal is to execute some code each time a method with a particular annotation completes its execution. I have the following:
#Aspect
public class MonitoringAspect {
#After("#annotation(MonitorExecution)")
public void onFinished(JoinPoint jp) {
System.out.println("called!");
}
}
The code of the MonitorExecution annotation is as follows:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MonitorExecution {
}
This happens inside a Spring4 application and I have declared the MonitoringAspect as a bean like:
<bean id="monitoringAspect" class="com.....MonitoringAspect" />
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="monitoringAspect"/>
</aop:aspectj-autoproxy>
I have a public method inside a general-purpose class (i.e. not managed by spring / not a component) that is annotated with the #MonitorExecution annotation. I have successfully verified that the aforementioned method gets called, but the aspect is never triggered. Any ideas what might be the issue?

aspectj-autoproxy means that proxy classes will be created for each Spring managed bean (using JDK dynamic proxies or CGLIB) and using these proxies you are able to intercept methods invocation. Thus, if your annotated method is method of a class outside Spring Context, aspect will not work
Despite it if you still want to intercept it, you will have to use AspectJ only or in conjunction with Spring. For second option you will have to enable load-time weaving in your spring configuration
Have a look documentation for details:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop

Related

Custom Annotation works only for ElementType.METHOD

I'm practising with customs annotations and I want to create a custom annotation that set a Math.random() value to an #Entity field (I know that I can do this in the constructor but I want to do with an annotation)
My Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.CONSTRUCTOR)
public #interface SetRandomPin {}
2.My Aspect
#Around("#annotation(com.testingAnnotations.annotattions.SetRandomPin)")
public void setUserPin(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {....}
}
In my #Entity when I put #SetRandomPin in the constructor, the method setUserPin is not firing.
Only If I change to ElementType.METHOD and I move my annotation to the UserService.class the method is firing.
I'm stuck here and I can't understand why is working with an ElmentType but not with another one.
Default Spring AOP doesn't offer constructor interception or private/protected methods. You can do it using AspectJ.
From docs
If your interception needs include method calls or even constructors within the target class, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework.

Override/disable Aspect on runtime

In my spring-boot application I have a dependency on external jar, which contains a class marked with annotation, on which #Aspect from this jar is being triggered.
I have dao method annotated with mu custom annotation:
#MyAnnotation
public void save(MyEntity entity)
{
super.save(entity);
}
I have an aspect, which has an advice, sending message after save() method is called:
#Aspect
public class MySuperAspect
{
#Autowired
MessageSender messageSender;
#Around("#annotation(MyAnnotation) && args(entity)")
public void sendMessage(MyEntity entity)
{
messageSender.send();
}
}
I do need Dao method from the jar, but I want to disable aspect for it.
Aspect is being created via Spring XML configuration, which is inside the jar I use as well.
I could modify the aspect itself, but it's undesirable as it's being used not only by my spring-boot app.
I tried:
Disabling xml configuration from scanning in my spring-boot app;
Changing xml config to annotations and filter it in scanning;
Adding #ConditionalOnExpression and #ConditionalOnProperty on aspect to be disabled by property;
As of now the only way which works is adding #Value annotation with property by which I may control logic inside the advice, but I'm curious is this the only way to do that or probably I'm missing something?
You need to stop spring boot from scanning this class... Because it must be configured to scan this aspect otherwise it wouldn't be picking up and applying the aspect.

Rest + Spring AOP + interface doesn't inject

I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.

Spring 3 MVC #Controller with AOP interceptors?

Anyone knows why apparently it is not possible to use AOP with annotated MVC Controllers? (see Post).
I have a #Controller that stops working as soon as I add a pointcut to it.
The problem is not that the interceptor is not being called, but rather the #Controller simply stops working (in the log you can see that instead of "Mapped URL path [/xx] onto handler 'Yyy'" you get a "no URL paths identified").
I know there is a mechanism for adding interceptors to controllers via the handlerMapping but my question is specific to AOP interceptors. Aren't annotated controllers just pojos in the Spring container as any other pojo? What is the difference? Why?
#Controller
#RequestMapping("/user")
public class RestTestImpl implements RestTest {
#RequestMapping(value="/", method={RequestMethod.GET})
public #ResponseBody String deleteUsers(String arg) {
return "Xxxxx";
}
}
In my servlet-Context I have:
<context:component-scan base-package="org.xxx.yyy"></context:component-scan>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
. . .
</bean>
And everything works just great.
But when I add:
<aop:config>
<aop:pointcut expression="execution(* org.xxx.*(..))" id="pc1"/>
<aop:advisor advice-ref="hibernateInterceptor" pointcut-ref="pc1" order="2" />
</aop:config>
The controller stops being a controller (no errors, simply it stops binding to the specified URL)!
From the Spring MVC Reference:
Note
When using controller interfaces (e.g. for AOP proxying),
make sure to consistently put all your
mapping annotations - such as
#RequestMapping and #SessionAttributes
- on the controller interface rather than on the implementation class.
Granted, this note is well hidden :-)
I ran into the same issue and found out the solution.
Indeed your controller (annotated by #Controller) and your aspects (annotated by #Aspect) should be in the same Spring context.
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
The above ssertion does not depend
on the way your declare your controllers/aspects (by manual XML declaration or annotation style)
on the proxying style you choose (JDK proxy or CGLIB)
I've tested all the combinations and they all work as long as the controller & aspects are in the same Spring context
My best guess without doing some serious digging is because Spring's AOP mechanism that you are using is wrapping the target classes in proxy classes which end up loosing their annotation or the original annotation gets dropped after weaving.
I am sure there is a better answer and I'll expand on mine as I think of a better more clear way to present it.

Spring AOP does not works in Tomcat and tcserver

I have an aspect which works fine when I run it from a unit test or through a stand alone application. However when I run it as a part of web application and host it on Tomcat the Aspects are not applied.
My aspect looks like
public class MyAspect {
#Around("within(com.service..*)")
public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {
//do something
Object obj = pjp.proceed();
//do something else
return obj;
}
}
I am able to solve this. The reason was that the aspect were getting processed by web application context and not by global application context so I have to restructure couple of things. I have detailed the steps here
#seanizer Spring does support within. It's true that it is only applied to methods and in within it will apply to methods of all the package and sub package of com.service. For details check the reference documentation here
Update: I'll leave this in, because it's still partially valid, even if it didn't help in your case. I'll edit a few places though, edits are marked like this or this.
If you're using Spring AOP, it can't work. Spring AOP only fully supports the execution pointcut. The within pointcut only works when it applies to method executions, for the full functionality of within you will need AspectJ (Spring AOP only uses some AspectJ pointcuts, but not the AspectJ weaver). Either through static compilation (usually through Maven or Ant) or through Load-Time-Weaving.
Also, your class is missing an #Aspect annotation.
How about move
<context:component-scan base-package="com.*" />
<mvc:annotation-driven/>
<aop:aspectj-autoproxy />
to servlet-mvc.xml?

Categories

Resources