How to intercept functions from those imported external packages by AOP - spring

For example, now I want to intercept the method split() of java.lang.String by AOP.
Is it possible?
I have tried some normal methods but it did not work.
#Aspect
public class TestAspect {
#Before ("execution (* java.lang.String.split(..))")
public void logBeforeString(JoinPoint joinPoint) {
System.out.println("SPLIT BEGIN");
}
}
Below is the configuration file :
<!-- Aspect -->
<aop:aspectj-autoproxy />
<beans:bean id="TestAspect" class="com.dong.partner.aspect.TestAspect" />
With other pointcuts in my own project, they work well without problems.
So anyone knows how to intercept the imported external packages?

No, nothing in java.lang can be advised using execution. See this question for a more detailed explanation.
So anyone knows how to intercept the imported external packages?
You're using <aop:aspectj-autoproxy /> which means that Spring is using proxy based AOP. Essentially, Spring is creating a wrapper around each of your beans if the bean is advised with AOP. When a method on one of your beans is called, it hits the proxy/wrapper first. The proxy decides whether it should invoke your bean directly or whether one or more aspects should be called.
There are limits to the type of advice you can use with proxy based AOP. To intercept calls from your code to non-bean classes you need to switch to compile time or load time weaving with aspectj and use call pointcuts instead of execution pointcuts. The aspectj compiler will rejigger your bytecode so that any calls from your code to java.lang.String are rewritten to invoke the call pointcut.
Interestingly, this question had the opposite issue that you're experiencing.

Related

Spring AOP logging

I have a j2ee web application running on Spring framework. I want to implement logging using log4j and Spring's AOP. I am able to log the public methods using custom annotation. I am not able to log private methods using custom annotation. can any one please give reference how to implement custom annotation for private methods.
Spring AOP
Spring AOP doesn't support interception of private methods.
11. Supported Pointcut Designators
Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are by definition not intercepted. For JDK proxies, only public interface method calls on the proxy can be intercepted. With CGLIB, public and protected method calls on the proxy will be intercepted, and even package-visible methods if necessary. However, common interactions through proxies should always be designed through public signatures.
Note that pointcut definitions are generally matched against any intercepted method. If a pointcut is strictly meant to be public-only, even in a CGLIB proxy scenario with potential non-public interactions through proxies, it needs to be defined accordingly.
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. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision.
AspectJ Source Weaving
You can intercept private methods by taking advantage of AspectJ source weaving. Here is a complete working example.

Spring AOP Method Interceptor vs Method Advice

I am new to AOP and I am trying to understand the difference between Method Interceptor and MethodAdvice(i.e. MethodBeforeAdvice or MethodAfterAdvice). To me looks like both are doing the same thing i.e. are called on method invocation. When should we use MethodInterceptor vs MethodAdvice.
Take a look at the definition of the org.aopalliance.interceptInterceptor interface (implemented by MethodInterceptor):
public interface Interceptor extends Advice {
}
It's easy to see that a MethodInterceptor actually IS an Advice.
The only difference between an Advice being defined in an #Aspect class and such an Interceptor is that Interceptor implementations can be added to and removed from Spring AOP Proxies at runtime (casting them to 'Advised'), whereas the Advice you're talking about is a more static construct. But their still essential to Spring AOP since their presence tells Spring which beans to wrap in a proxy object during application context startup.

Using Spring AOP uses underneath aspectj?

Hy,
Reading a lot about Spring AOP vs AspectJ, I still have some doubts:
1.)When using Spring AOP with classes annotated with #Aspect and using "aop:aspectj-autoproxy" tag , it can be said that we are using just the annotations of aspectj or besides that it is being used AspectJ too for the weaving?
2) Its said that AspectJ has better performance because the weaving is in compilation time, it means that the target class files are physically changed inserting the aspects in them? is it not a bit aggressive?
3)It said that Spring uses proxys for AOP, so, I undertand that when you get a bean from Spring, Spring builds a proxy in memory that has already inserted the aspects in it, right?
So why is it said that when a method from your proxy bean calls other method in the proxy, the last method will not have aspects?
Thanks
1) using aspectj-autoproxy means that #Aspectannotations are recognized, but Spring proxies are still being created, see this quote from the documentation:
Do not be misled by the name of the element:
using it will result in the creation of Spring AOP proxies. The
#AspectJ style of aspect declaration is just being used here, but the
AspectJ runtime is not involved.
2) AspectJ supports load time weaving, byte code weaving and compile time weaving. There should no difference in performance, it's just a different point in time to weave the aspect in (compilation, third party jars available, class load time), see this answer for further details.
It is actually more transparent once it's set up to have the aspects weaved at these moments, with runtime proxies there are problems when a bean calls itself using this.someMethod, the aspects don't get applied because the proxies get bypassed (#Transactional/#Secured does not work, etc.).
3) Have a look at this picture from the documentation:
With runtime proxies (non AspectJ), Spring leaves the bean class untouched. What it does is it creates a proxy that either implements the same interface as the bean (JDK proxy), or if the bean implements no interface then it dynamically creates a proxy class with CGLIB (subclass of bean).
But in both cases a proxy is created that delegates the calls to the actual bean instance. So when the bean call this.methodB() from methodA, the proxy is bypassed because the call is made directly on the bean and not on the proxy.
Spring AOP can be configured with AspectJ-sytle, ie annotations are parsed to build configuration but AspectJ compiler is not used for weaving. Only a subset of AspectJ annotations and poincut definitions can be used with Spring AOP.
Maybe, but I don't know any class that has complained. However, is possible that some classes don't allow re-weaving when modified by other bytecode tools.
Inner calls are not proxied because they call on this.method() (with this = the target bean begin proxied) and not on proxy.method() so the proxy has no chances to intercept the call. However, Spring AOP proxies usually notices when a target method return this and return itself instead, so calls like builder.withColor(Color.RED).withHat(Hat.Cowboy) will work. Note that in Spring AOP there are always two classes involved: the proxy and the target.

SpringAOP, load-time-weaver, strange behavior

in this moment i am facing one problem and really dont know what i am doing wrong. I am coding logging for my webservice using Spring framework and AOP in #AspectJ style. I got two bundles - background and frontend. In background bundle I have LogAspect, which look like this:
#Aspect
public class LogAspect {
#Pointcut("#annotation(logMethod)")
public void logMethodAnnotated(LogMethod logMethod){}
#Before("logMethodAnnotated(logMethod)")
public void beforeLogMethodAnnotated(JoinPoint jp){
//actions
}
#After("logMethodAnnotated(logMethod)")
public void afterLogMethodAnnotated(JoinPoint jp){
//actions
}
}
and META-INF/spring/background-osgi.xml:
<context:annotation-config />
<context:component-scan base-package="simon.background"/>
<context:load-time-weaver />
and also META-INF/aop.xml:
<!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="simon.background.*"/>
<include within="simon.frontend.controller.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="simon.background.log.LogAspect"/>
</aspects>
</aspectj>
In frontend bundle I've just put into aplicationContext.xml <context:load-time-weaver aspectj-weaving="on" />. But the code is acting very strange. I found out, that there is some problem, when I put into my advice methods JoinPoint as argument. (I mean, when I got advice methods without arguments, so there were no JoinPoin in method header, everything has been working fine and advices has been running before and after #LogMethod (my annotation, which I use to say, that i want to log this method) annotated methods). But now it is working like this:
- when I start server and so that the bundles are deployed for the first time, then the advices are run just for methods, they are #LogMethod annotated and belongs to background bundle, but not for annotated methods in frontend.controller.
- and in addition, when I have done some changes in one of my controllers, saved it and deployed just frontend bundle, then when I run #LogMethod annotated method, I got this error:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.LinkageError: loader constraint violation: when resolving method "simon.background.log.LogAspect.afterLogMethodAnnotated(Lorg/aspectj/lang/JoinPoint;)V" the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) of the current class, simon/frontend/controller/HuhController, and the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) for resolved class, simon/background/log/LogAspect, have different Class objects for the type /aspectj/lang/JoinPoint;)V used in the signature
Any ideas what is going on and how can i fix it, so my program will be able to run advices correctly?
One additional note, it could maybe help: When I run this in Debug mode with advices without JoinPoint argument, I realized, that both advices were running twice for one method.
On running twice, could it be because you are using both and
at the same time? Difference between <context:annotation-config> vs <context:component-scan>
Your pointcut has been triggered twice because your expression only constraints annotation type. When a method is called, call() and execution() are both match this expression so.
You can use #annotation(xxx) && execution(* *(..)) on your point cut to restrict the condition on execution only.

Does this annotation work for Spring declarative transaction

As far as I know, Spring uses JDK to generate dynamic proxy for the classes that implement any inferface while use Cglib to generate dynamic proxy for the classes that do not implement any inferface. For decarative transcation, Spring uses proxy to add transaction aspect. Please take a look at the code below:
interface Demo {
void methodA();
}
public class DemoImpl implements Demo{
#Transactional
public void updateA() {}
#Transactional
public void updateB() {}
}
I think updateA can work well with transaction. But how about updateB method? Does the #Transactional work for it?
Maybe my understanding is not correct. It's great if the related Spring source code is provided to explain how Spring use JDK/cglib to proxy the class and interface. Thanks
I have the config in the xml:
<tx:annotation-driven transaction-manager="transactionManager" />
JDK dynamic proxy
In this case your bean is wrapped with a proxy implementing Demo interface. From that moment you can only use that interface. Trying to inject or fetch bean of DemoImpl type will result in dreadful Abstract DAO pattern and Spring's "Proxy cannot be cast to ..." problem!
This kind of answers your question - you can only access updateA() and this is the only transactional method. Annotation around updateB() is ignored.
However if you call updateB() from updateA() it will be transactional because it will bind to a transaction started by updateA() (with default transaction propagation).
CGLIB proxy
In this case the interface is ignored. cglib will create a subclass of DemoImpl (obviously also implementing Demo interface) and apply transaction behaviour on both update*() methods. Now if you inject bean of type DemoImpl (interface is not needed in this case at all and Impl suffix is ugly) you can safely and transactionally call both methods.
See my article: Spring pitfalls: proxying and Spring AOP riddle for greater details.

Resources