AOP can pointcut like #Controller or #Service.
But it doesn't work well on Class without spring's annotation.
package com.erp.module;
#Slf4j
public class SalesOrderModule {
public void cancel(){
log.info("test");
}
public static SalesOrderModule init(int type) {
SalesOrderModule salesOrderModule = new SalesOrderModule(salesOrder);
*****
return salesOrderModule;
My Aspect.java like below
#Aspect
#Component
#Slf4j
public class WebLogAspect {
#Pointcut("execution(public * com.erp.controller.*.*(..)) || execution(public * com.erp.module.*.*(..))")
public void logPointCut() {
}
I invoke cancel like below:
SalesOrderModule so = SalesOrderModule.init(3);
so.cancel();
I know this problem is relative to proxy. But how can I
Spring Docs says:
Thus, for example, the Spring Frameworkâs AOP functionality is normally used in conjunction with the Spring IoC container. Aspects are configured using normal bean definition syntax (although this allows powerful "autoproxying" capabilities): this is a crucial difference from other AOP implementations. There are some things you cannot do easily or efficiently with Spring AOP, such as advise very fine-grained objects (such as domain objects typically): AspectJ is the best choice in such cases. However, our experience is that Spring AOP provides an excellent solution to most problems in enterprise Java applications that are amenable to AOP.
So if you need to intercept non-spring managed code, you need to use AspectJ instead of Spring AOP. TBH, I didn't need that so far.
Related
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 { }
I'm developing a java (JDK1.6) application with Spring framework(4.0.5) and AspectJ for AOP Logging.
My Aspect classes work fine but I can't create a pointcut for constructor object.
This is my object:
#Controller
public class ApplicationController {
public ApplicationController(String myString, MyObject myObject) {
...
}
...
..
.
}
This is my Aspect class:
#Aspect
#Component
public class CommonLogAspect implements ILogAspect {
Logger log = Logger.getLogger(CommonLogAspect.class);
// #Before("execution(my.package.Class.new(..)))
#Before("execution(* *.new(..))")
public void constructorAnnotatedWithInject() {
log.info("CONSTRUCTOR");
}
}
How can I create a pointcut for my constructor object?
Thanks
Sotirios Delimanolis is right insofar as Spring AOP does not support constructor interception, you do need full AspectJ for it. The Spring manual, chapter 9.8 Using AspectJ with Spring applications, describes how to use it with LTW (load-time weaving).
Furthermore, there is a problem with your pointcut
#Before("execution(* *.new(..))")
Constructors do not have return types like methods in AspectJ syntax, so you need to remove the leading *:
#Before("execution(*.new(..))")
Is it possible to use #DeclareMixin with Spring AOP? Or do they only support #DeclareParents?
I want to write an aspect that mixes in the java.beans.PropertyChangeSupport into a java bean:
public class PropertyChangeSupportWithInterface extends PropertyChangeSupport
implements IObservableBean {
public PropertyChangeSupportWithInterface(Object sourceBean) {
super(sourceBean);
}
}
(IObservableBean simply contains all public methods from the PropertyChangeSupport)
#Aspect
#Named
public class ObservableAspect{
#DeclareMixin("#ObservableBean *")
public static IObservableBean createDelegate(Object object) {
return new PropertyChangeSupportWithInterface(object);
}
}
It seems that this aspect is never used, which makes me think that the #DeclareMixin is not supported by the runtime weaving done by Spring AOP.
Is there any way to get this working with Spring AOP?
You can find a (not) running example here (Maven multi module project):
https://github.com/BernhardBln/SpringAOPObservableBean
See the (only) test case in the springaop-observable-bean-aspect submodule.
No, it's not supported by Spring AOP out the box. I see two options:
Create a DeclareMixinIntroductionInterceptor for Spring AOP.
Switch to Aspectj
I think that PropertyChange interface fits better in Aspectj because usually you will create a lot of proxies for prototype beans and them could be created easily out of the framework, by an ORM for example.
Edit
However I'm interested in this feature too and I already done some work for use it:
A DelegateFactoryIntroductionInterceptor to support creating delegates from the aspect instance.
A DeclareMixinAdvisor to join the inteceptor with the type pattern.
A DeclareMixinAspectJAdvisorFactory to support the DeclareMixin annotation.
To use it you only need to declare a bean of type DeclareMixinAutoProxyCreatorConfigurer
for configuring the AnnotationAwareAspectJAutoProxyCreator with the AdvisorFactory above.
I'm just testing, but seem that work fine.
I am having trouble getting multiple aspects to fire in a specific order. I am using the RequestProcessor to do certain things on every incoming request on my controllers, which have a certain parameter
Then I have some specific annotations that I will be adding to only certain methods within my controllers.
FYI I am using Eclipse, Tomcat, Maven and spring with java/annotation based configs. I use Tomcat and the WebApplicationInitializer to load my context, dispatcher, listeners etc. I have no web.xml. I can post that or the pom.xml if needed too.
The problem I am getting is that a method that satisfies both the ProcessRequest pointcut and the someAnnotation pointcut is firing the someAnnotation method first even though the order is specified to fire ProcessRequest first. There is some properties set in the ProcessRequest that is needed in some other annotations.
Here is a simplified version of my code.
Spring Config Class
#Configuration // Enable Spring Annotation Configuration. Equivalent to <context:annotation-config/>
#EnableAspectJAutoProxy
#EnableCaching // Enable Spring caching
#EnableWebMvc // Enable Spring MVC Annotation. Equivalent to <mvc:annotation-driven />.
#ComponentScan(basePackages = {"xxx.yyy.zzz"}) // Scan for Spring Components. Equivalent to <context:component-scan>
public class WebAppConfig extends WebMvcConfigurerAdapter {
// Other Bean logic here
#Bean
public RequestProcessor requestProcessor() {
return new RequestProcessor();
}
#Bean
public AnnotationAspect annotationAspect() {
return new AnnotationAspect();
}
}
Aspect #1
#Aspect
#Order(0)
public class RequestProcessor {
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
Aspect #2
#Aspect
#Order(1)
public class AnnotationAspect {
#Before("#annotation(xxx.yyy.zzz.annotation.SomeAnnotation)")
public void someAnnotation() {
// Log for this annotation
}
// Some other annotation methods here
}
Also tried this format implements Ordered
#Aspect
public class RequestProcessor implements Ordered {
#Override
public int getOrder() {
return 0;
}
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
I read over this post and some others but couldn't find anything relevant that worked.
Ordering aspects with Spring AOP && MVC
****UPDATE****
So I have been reading through the AspectJ docs on declaring precedence so I thought I would give it a whirl. I created a simple aspect that only declares precedence and it works just fine.
Here is my Precedence Aspect:
public aspect AspectPrecedence {
declare precedence : RequestProcessor, SomeAspect;
}
I am not going to submit this as answer just yet because I would like to understand why the annotation or "implements Ordered" are not functioning properly in my project.
Any insight would be greatly appreciated. Thanks!
****UPDATE 2****
For reference this works locally in my eclipse environment and seemed to work when deployed to AWS via WAR file.
#Aspect
#DeclarePrecedence("RequestProcessor, SomeAspect")
public class RequestProcessor {
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
When using Eclipse with AspectJ support that automatically enables compile time weaving in your IDE. Which means the aspects get woven into your byte code, opposed to Spring which uses proxies to apply aspects.
Using an aspect to declare precedence or using #DeclarePrecedence will only work when using either compile or load time weaving (the latter can be enabled by specifying <context:load-time-weaver/> depending on your container might require some additional configuration). However both should work (you might need to specify the AspectJ compiler as a compiler for the #Aspect classes instead of the default java compiler).
#Order and Ordered only work for the proxy based solution and are ignored by AspectJ.
I think the problem could be that you're using LTW with AspectJ instead AOP with Spring, as #Order is defined for Spring, the container(AspectJ) is not able to determine the ordering of both the advices, so try one of these:
Try flipping the order of #Aspect and #Order annotations
You can try the annotation #DeclarePrecedence from AspectJ and then configuring your aspects into the aop.xml
<aspects>
<aspect name="your.package.RequestProcessor"/>
<aspect name="your.package.AnnotationAspect"/>
<concrete-aspect name="my_aspect_configuration_precedence"
precedence="*..*RequestProcessor, *"/>
</aspects>
I don't know if it's going to work but expect to give you a pointer on that
I am new to Spring AOP.
Using annotation based Spring configuration:
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass=true)
#ComponentScan({"sk.lkrnac"})
Aspect:
#Aspect
#Component
public class TestAspect {
#Before("execution(* *(..))")
public void logJoinPoint(JoinPoint joinPoint){
....
}
}
Spring compoment:
package sk.lkrnac.testaop;
#Component
public class TestComponent{
#PostConstruct
public void init(){
testMethod();
}
public void testMethod() {
return;
}
}
How can I intercept all public methods that are called by Spring framework itself? (e.g. TestComponent.init() during creation of the TestComponent instance by Spring)
Currently I am able to intercept only TestComponent.testMethod() by invoking:
TestComponent testComponent = springContext.getBean(TestComponent.class);
testComponent.testMethod();
This is a common issue you run into with Spring AOP. Spring accomplishes AOP by proxying advised classes. In your case, your TestComponent instances will be wrapped in a run-time proxy class that provides the "hooks" for any aspect advice to be applied. This works very well when methods are called from outside the class, but as you have discovered it doesn't work on internal calls. The reason is that internal calls will not pass the proxy barrier, thus will not trigger the aspect.
There are primarily two ways around this. One is to fetch an instance of the (proxied) bean from the context. This is what you have already tried with success.
The other way is to use something called load-time weaving. When using this, AOP advices are added to a class ("weaved" into it) by a custom class-loader by injecting byte-code into the class definition. The Spring documentation has more on this.
There is a third way, which is called "compile time weaving". In this scenario, your AOP advices are statically weaved into each advised class when you compile it.
You can't intercept init() without any explicit means, please see the SpringSource Jira for details.
You can also try to call inner testMethod() from init() by self via proxy object like Don explained in https://stackoverflow.com/a/5786362/6786382.