I understand that Spring AOP is very limited in its abilities (it can only cut into public methods of classes that are Spring beans, and only when those methods are called from outside the class). But now I've discovered another baffling limitation when interfaces are involved.
Normally, if a class is subclassed, Spring AOP has no problem cutting into all of their methods (even overridden ones):
public class A {
public void methodA() { } //OK, can cut in
}
public class B extends A {
#Override
public void methodA() { } //OK, can cut in
public void methodB() { } //OK, can cut in
}
But when we add an interface into the mix, things get pretty bad for Spring AOP:
public interface I {
public void methodA();
}
public class A implements I {
#Override
public void methodA() { } //OK, can cut in
public void methodB() { } //Fail, cannot see or cut into this method
}
public class B extends A {
#Override
public void methodA() { } //Fail, cannot see or cut into this method
public void methodC() { } //Fail, cannot see or cut into this method
}
First of all, Spring AOP can only cut into methods that are in the interface, anything else - it cannot see. Second, it can only cut into the method that directly implements the interface's method - A.methodA(). It cannot cut into the same method overridden by B.
I am using a generic pointcut expression "execution(* method*(..))" to cut into all possible methods, so it's not an expression issue.
Is there any way around this limitation? Or should I just forget about Spring AOP and use a different approach?
UPDATE:
Ok, I have found the real cause of the problem. I was actually relying on Intellij IDEA's AOP plugin to test this. It's supposed to link the pointcut to all affected methods. But it was using the 'old', dynamic JDK proxy strategy instead of the new, CGLIB strategy. So it wasn't linking it to all methods, but when I actually ran my program, it would cut into all methods correctly.
I'm using Spring Boot 2, which uses the 'new' CGLIB strategy. But on SB1 it might still use the 'old' dynamic JDK proxy strategy, so it might still not work there.
Spring will use either dynamic proxy or cglib to implement AOP.
Cglib is picked if there is no interface, then it will effectively create a subclass of the target class, and override all methods in the target class. With this way all methods could be cut in, except final and static ones.
In case the target class is with interface, then Spring might use a dynamic proxy using one of the interface, and apprantly this will only affect the methods declared in the interface.
Before spring-boot 2.0, dynamic proxy is the default strategy. Now Cglib is the default strategy after spring-boot 2.0.
It seems to me spring probably take the dynamic proxy approach in your case. You could add spring.aop.proxy-target-class: true in your application.yaml to force use Cglib.
In case you still have issue, it's better to post more complete code snippet showing how the mothods are invoked.
Related
As we all know, the self-invokation of bean's method is not working in Spring without AspectJ.
See this question for example.
I think this is because the Spring-created proxy calls the target object's methods using delagate pattern. Like this:
class MyClass {
#Autowired
private MyClass self; // actually a MyProxy instance
#Transactional // or any other proxy magic
public void myMethod() {}
public void myOtherMethod() {
this.myMethod(); // or self.myMethod() to avoid self-invokation problem
}
}
class MyProxy extends MyClass { // or implements MyInterface if proxyMode is not TARGET_CLASS and MyClass also implements MyInterface
private final MyClass delegate;
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
delegate.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
delegate.myOtherMethod();
}
}
Am I right?
With this code:
public void myOtherMethod() {
this.myMethod();
}
this.myMethod() will bypass the proxy (so all #Transactional or #Cacheable magic) because it is just internal delegate's call... So we should inject a MyClass bean (which is actually is MyProxy instance) inside MyClass and call self.myMethod() instead. It is understandable.
But why the proxy is implemented this way?
Why it is not just extends the target class, overriding all public methods and calling super instead of delegate?
Like this:
class MyProxy extends MyClass {
// private final MyClass delegate; // no delegate
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
super.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
super.myOtherMethod();
}
}
It should solve the self-invokation problem, where this.myMethod() bypasses the proxy, because in this case this.myMethod(), invoked from MyClass.myOtherMethod() (we remember that MyClass bean actually is MyProxy instance), will invoke overriden child's method (MyProxy.myMethod()).
So, my main question is why it is not implemented this way?
Your assumption that Spring AOP uses delegation for its proxies is correct. This is also documented.
Using CGLIB, you can theoretically use proxy.invokeSuper() in order to achieve the effect you want, i.e. that self-invocation is registered by the aspect implemented by the proxy's method interceptor (I am using Spring's embedded version of CGLIB here, thus the package names):
package spring.aop;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class SampleClass {
public void x() {
System.out.println("x");
y();
}
public void y() {
System.out.println("y");
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if(method.getDeclaringClass() == Object.class)
return proxy.invokeSuper(obj, args);
System.out.println("Before proxy.invokeSuper " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After proxy.invokeSuper " + method.getName());
return result;
}
});
SampleClass proxy = (SampleClass) enhancer.create();
proxy.x();
}
}
Console log:
Before proxy.invokeSuper x
x
Before proxy.invokeSuper y
y
After proxy.invokeSuper y
After proxy.invokeSuper x
This is exactly what you want. The problem starts, however, when you have several aspects: transactions, logging, whatever else. How do you make sure that they all work together?
Option 1: Each aspect gets its own proxy. This obviously will not work unless you nest the proxies into each other according to aspect precedence. But nesting them into each other means inheritance, i.e. one proxy would have to inherit from the other outside-in. Try proxying a CGLIB proxy, it does not work, you get exceptions. Furthermore, CGLIB proxies are quite expensive and use perm-gen memory, see descriptions in this CGLIB primer.
Option 2: Use composition instead of inheritance. Composition is more flexible. Having one proxy to which you can register aspects as needed solves the inheritance problem, but also means delegation: The proxy registers the aspects and calls their methods during runtime in the right order before/after the actual real object's code is executed (or not, if an #Around advice never calls proceed()). See this example from the Spring manual about manually registering aspects to a proxy:
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an #AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an #AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
As to why the Spring developers chose this approach and whether it might have been possible to use the one-proxy approach but still make sure that self-invocation works like in my little CGLIB sample "logging aspect" above, I can only speculate. You can maybe ask them on the developers mailing list or look into the source code. Maybe the reason was that CGLIB proxies should behave similarly to the default Java dynamic proxies so as to make switching between the two for interface types seamless. Maybe the reason is another one.
I did not mean to be rude in my comments, only straightforward, because your question is really not suited to StackOverflow because it is not a technical problem to which someone can find a solution. It is a historical design question and rather philosophic in nature because with AspectJ a solution to your technical problem (self-invocation) beneath the actual question already exists. But maybe you still want to dive into the Spring source code, change the Spring AOP implementation from delegation to proxy.invokeSuper() and file a pull request. I am not sure such a breaking change would be accepted, though.
In addition, you will not able to use Inheritance + super in the following cases:
What about if the RealSubject is final, so the proxy will can NOT extends it
What about if the Proxy needs to extend something other than the RealSubject
What about if you need to hide some functionality (methods) inside the RealSubject
Prefer Composition over Inheritance (recommended by many developers)
Is it a bad practice to have a Spring Service break down its functionality by implementing multiple interfaces and then having Spring inject that one Service instance using the interface that declares only the required methods where needed?
Like:
public interface OperationsService1 {
public void operation1();
public void operation2();
}
public interface OperationsService2 {
public void operation3();
public void operation4();
}
#Service
public class OperationsServiceImpl implements OperationsService1, OperationsService2 {
public void operation1() {}
public void operation2() {}
public void operation3() {}
public void operation4() {}
}
and then in the calling class:
#Autowire
private OperationsService1 ops1;
or
#Autowire
private OperationsService2 ops2;
This is more a matter of design than a matter of Spring from my point of view. Generally, a class should be responsible for a single functionality (see SRP on wiki). So one service class should implement one service interface.
and then having Spring inject the Service instance using the interface
that declares only the required methods where needed?
First of all I feel like you are confused. In your example there won't be an instance for each interface. When you call
#Autowire
private OperationsService1 ops1;
#Autowire
private OperationsService2 ops2;
they will both point to the same OperationsServiceImpl class because the bean is singleton by default. What you have here is one instace and two interfaces which point to it. By autowiring the interfaces it means that for the first interface you can call only some of the methods in the bean, with the 2nd interface some other methods of the same bean.
It it a good practice?
I don't think so, usually one would use an interface with multiple object instances with various functionality which is not the case here as explained above. It's gonna get even more messy if other classes start implementing these interfaces and you have to use #Qualifier to distinguish between them. If you want a clean solution separate the OperationsServiceImpl into two separate classes and each of them implement the corresponding interface. It would be less complex and easier to support for new developers.
I have to apply Spring AOP for legacy code without changing anything in the existing code. There is no bean concept and the objects are created using new keyword, so no scope of using applicationContext.getBean("beanName"). Also the pointcuts will be taken as input from end user and there will be a common aspect class.
For eg.
package package1;
public class Demo1 {
public void method1()
{
System.out.println("From method1");
}
public void method2()
{
System.out.println("From method2");
}
}
package package2;
public class Demo2 {
public void method3()
{
System.out.println("From method3");
}
public void method4()
{
System.out.println("From method4");
}
}
package aspects;
public class SpringAspect {
public void beforeAdvice(JoinPoint jointPoint)
{
System.out.println("Before method : "+jointPoint.getSignature());
}
}
Pointcuts taken as input from end user are as follows and their before advisor method is beforeAdvice() from aspects.SpringAspect class :
execution(* package1.Demo1.method1(..))
execution(* package2.Demo2.method4(..))
Also if it is not possible using Spring AOP, how can I use AspectJ during runtime for the same.
First of all, your so-called aspect is missing aspect-related annotations such as #Aspect and #Before, without which it is just a POJO class. It will never be executed or even recognised as an aspect.
Second, Spring AOP is a proxy-based framework which only works in connection with Spring components, not with POJO classes. You need AspectJ in order to solve your problem. (Have you ever read a tutorial or the Spring or AspectJ manual, by the way? I guess you have not.)
Furthermore, why on earth would you want a user to enter pointcuts during runtime? Should you not know where to apply your aspects a bit earlier? Even if I would show you a solution creating aspects on the fly, they would not be very valuable because even load-time weaving needs to instrument your Java code during class-loading. If the target classes are already loaded, there is no way to apply aspects on them post factum.
Maybe you should explain what you want to achieve and not ask how to do something technically which does not make sense and will not work, thus not solve your problem anyway.
If you want a more dynamic way to define your pointcuts other than hard-coding them within your aspects, you can create an abstract base aspect with an abstract pointcut and define the concrete pointcut in an aop.xml file which is used for load-time weaving, as described in the AspectJ documentation.
I am currently experimenting with Spring and its AOP features.
What I would like to know is if it is possible to extend the expression language of pointcut definition somehow...
I am quite familiar with the standard behaviour and usage of pointcut designators Spring provides but for my needs I would like to implement my own one.
Say we have a method in our aspect:
#Aspect
public class AspectClass {
#Before("execution(* *.get*(..)) && #annotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation) {
System.out.println("Doing stuff!");
}
}
Now what I would like is something like this:
...
#Before("execution(* *.get*(..)) && #myAnnotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation){
...
Where the myAnnotation(..) token is my custom extension of the expression language.
When I delved into Spring implementation I found where the parser resides and the fact it is hard-coded into AspectJExpressionPointcut implementation. Hence providing a custom implementation of said parser and sticking it someplace in some bean initialization routine seems like a no-no.
Exemplary usage of this extension would be for example matching a method by it's annotation, disregarding proximity of this annotation in the object hierarchy. So it would match a method that is overriden and whose annotation is defined on the parent's implementation.
public abstract class Superclass {
#SomeAnnotation
public abstract String getValue();
}
public class TheClass extends Superclass {
#Override
public String getValue() { // <- this would get advised by Spring using formerly defined aspect
// return some stuff
}
}
I know that I can reflect the method in the advice and check if the annotation is present on some method of some superclass, but I would like to encapsulate this process and offer it for convenient usage.
Have you guys stumbled upon something like this & can you offer me a solution (if it is possibe) / explanation (if it is not)? :-)
Thanks in advance, Janek.
I need to test some security related classes that depend on Spring Security. This code makes use of SecurityContextHolder.getContext() which is static. How can I test the calling method without setting up an entire security context?
We are using JUnit 4 with Mockito. Mockito was pretty explicit in it's FAQ that static methods where not supported. Is there an alternative? An answer for the Spring Security case would be nice, but I am looking for a solution to the more general problem.
Have a look at PowerMock it will allow you to mock out static method, constructors and do all sorts of other crazy things you wouldn't normally be able to do with java. It integrates with most mocking libraries including mockito (look here http://code.google.com/p/powermock/wiki/MockitoUsage13 for an example).
In general I've found this to be a very useful library to have in your testing toolbox (when coding java). The only caveat is that since this library plays around with your bytecode, if you have other libraries that do bytecode instrumentation/manipulation you can run into trouble, but you won't know until you try.
You can refer to the following issue and inject org.springframework.security.core.context.SecurityContextHolderStrategy instance which functionality is available since Spring Security 3.0.
You should be able to simply call SecurityContextHolder.setContext() with a mocked SecurityContext in your setupt code. SecurityContextHolder just seems to be a thin wrapper around a ThreadLocal, so it should work fine.
Maybe refactoring code so it accepts some interface instead of getContext()? You'll need impl which will delegate all work to context, though.
UPDATE: Code will look like
interface SecurityContext {
void foo();
}
class SpringSecurityContext implements SecurityContext {
public void foo() {
// call spring static method here
}
}
class TestSecurityContext implements SecurityContext {
public void foo() {
// test case logic here
}
}
class SecurityContextClient {
private final SecurityContext context;
public SecurityContextClient(SecurityContext context) {
this.context = context;
}
void useSecurity() {
context.foo();
}
}