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.
Related
I know that you can use the annotation #Mapper(componentModel = “spring”) to use Spring to manage/inject the mapper dependency. My question is, are there any advantages to this approach vs declaring an instance variable within the mapper class itself:
#Mapper
public interface SomeMapper {
SomeMapper INSTANCE = Mappers.getMapper(SomeMapper.class);
SomethingElse mapSomethingToSomethingElse(Something something);
}
...
// Clients using mapper
SomethingElse result = SomeMapper.INSTANCE.mapSomethingToSomethingElse(input);
When using Spring dependency injection to inject mappers, you will end up adding extra constructor arguments/instance fields which is desirable as it makes it more obvious that a class is starting to rely on too many dependencies and should most likely be refactored (eg. think about Sonar's rule 'Too many parameters').
Another advantage is that since you're registering the mappers as beans in the Spring context, you can leverage the framework capabilities to easily inject dependencies in your mappers, customize all mappers at runtime through the BeanFactoryPostProcessor and rely on all the other framework abstractions that seem fit.
I'd say since you're already using Spring in your application, there is pretty much no reason to not register the mappers as Spring beans and inject them the DI way rather than turning them into static utils.
I'm trying to use Spring AOP to add logging to methods coming from a third party library. So there is a class, ProxyServlet, that is being used by my Spring Boot application, and I just want to apply logging to it.
#Pointcut("within(com.common.httpproxy.ProxyServlet)")
private void proxyServlet() {}
#Before("proxyServlet()")
public void testLog() {
log.info("THIS IS WORKING");
}
This is just some test AOP code right here. I know that my Spring AOP is set up, because I can get log output for any classes included in my codebase. However, I can't get log output for any classes from a third party library, like the ProxyServlet.
Is there anything I can do to get this AOP advice to work?
You should annotate the class containing this code with:
#Aspect
#Component
Assuming that the ProxyServer instance is a bean, you can achieve it by defining an aspect for the logging something like below.
#Aspect
public class LoggingAspect {
#Before(execution(* the.package.ProxyServlet.*(..)))
public void loggingAdvice(JoinPoint joinPoint){
System.out.println("Started loggingAdvice on method="+joinPoint.toString());
System.out.println("The aruguments are =" + Arrays.toString(joinPoint.getArgs()));
}
}
Please note that it is not necessary to have a custom point-cut like #LoggingAdvice here and annotate the target method using it (I am pointing it because you mentioned that the class is in third party library by which means you are expressing the concern that you may not be able to annotate meothod(s) with a pointcut) . Custom point-cuts are useful when you define widely applicable Aspects and limit the application of it to certain joint pints (thru the custom pointcut)
As your target is a single class and is third party library, you are good without a custom point-cut but with an aspect specifically targeting the required class.
The above define Aspect will be executed for every method defined in the ProxyBean class.
To use jamon in spring, it's described to use JamonPerformanceMonitorInterceptor and put it to springs AOP-mechanism via a applicationContext.xml. It's explained, and there's an example within the tests in it's sources. Unfortunately, I want to build a spring-boot application without any xml-configuration.
Is it possible to use some annotations to include the JamonPerformanceMonitorInterceptor to spring?
Better late than never...
I had the very same situation: I needed to configure JAMon without any XML configuration. Most of the examples online (including the comments in the JAMon source code) advertise XML configuration flexibility, but I couldn't find any examples with annotation based configuration. Also annotation-based configs are not necessarily less flexible, they just need to be conceptually separated and not confused with functional parts of the application. I think such advisor can be a good example:
#Component
public class MonitoringAdvisor extends AbstractPointcutAdvisor {
private final StaticMethodMatcherPointcut pointcut = new StaticMethodMatcherPointcut() {
#Override
public boolean matches(Method method, Class<?> targetClass) {
return targetClass.isAnnotationPresent(RestController.class);
}
};
#Override
public Pointcut getPointcut() {
return this.pointcut;
}
#Override
public Advice getAdvice() {
return new JamonPerformanceMonitorInterceptor(true, true);
}
}
This advisor would let Spring/AOP know to run JAMon monitoring advice on any method of Spring bean annotated with #RestContrller. This advisor should be configured/added to the same Spring context as rest controllers.
Note, that in my case I specifically wanted to monitor my rest controllers. One can adapt the advisor according to his/her own needs. (In my code I use a more advanced/configurable version of the presented advisor)
Is this Spring Boot sample application helpful?
Here is the relevant part of the Spring AOP manual.
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.
I have an elaborate Spring bean setup for integration tests. Now I'm looking into writing a Robot library to expose my test data creation / behavior execution / assertion methods to Robot tests.
However what I understand from the Robot Framework user guide is that Robot can only instantiate library classes by calling a constructor. This is a bummer because I'd rather have my instances managed by Spring.
Ideally, I'd want to be able to give Robot the path to the application context and the bean name for the library. Failing that, I'd want Robot to be able to invoke a static factory method rather than a constructor, so I'm not forced to create a new instance.
One workaround I thought of is to create the Spring context in a static initializer and wire my dependencies by fetching beans from that context.
My original class looks like:
public class MyAwesomeTests {
#Autowired
private ThisHelper thisHelper;
#Autowired
private ThatHelper thatHelper;
// implementations of test steps and such
}
So I would change the above #Autowired fields to be protected, and create a subclass that statically initializes the Spring context and defines a Robot-friendly constructor:
public class RobotFriendlyTests extends MyAwesomeTests {
private static final ApplicationContext CONTEXT = new ClassPathXmlApplicationContext(...);
public RobotFriendlyTests() {
this.thisHelper = (ThisHelper) CONTEXT.getBean("thisHelper");
this.thatHelper = (ThatHelper) CONTEXT.getBean("thatHelper");
}
}
This should work, but it feels somewhat clunky. Is there a better way I should consider? Better yet, is there a Robot extension that already does this for me?
Have you thought about using Spring #Configurable, then even instances created by a normal new will become spring managed beans.
#See Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
There's a Robot Framework extension that supports using Spring to wire test libraries, take a look at: http://code.google.com/p/robotframework-javalibcore/wiki/SpringLibrary
I am not entirely sure whether it supports your case since I am not familiar at all with Spring.