SpringAOP采用java语言作为AOL,SpringAOP属于第二代AOP,采用动态代理以及字节码生成技术实现。动态代理与字节码生成技术,在运行时为目标对象生成一个代理对象,并把横切逻辑织入到这个代理对象中。使用时使用了这个织入横切逻辑的代理对象,而非目标对象本身。
代理模式
静态代理
代理处于 访问者 与 被访问者 之间,可以隔离这两者之间 的直接交互,访问者与代理交互,就好像与被代理对象交互一样。代理通常拥有被代理者的全部职能。这样做的好处:一个是减轻了被访者的负担;另外,在请求转发给真正的对象(target Object)之前或者之后,可以加入比如安全限制、监控等等逻辑。
可参考:
/**
*
* @author zhangsh
*
*/
public interface ISubject {
void request();
}
/**
*
* @author zhangsh
*
*/
public class SubjectImpl implements ISubject {
@Override
public void request() {
System.out.println("request");
}
}
/**
*
* @author zhangsh
*
*/
public class SubjectProxy implements ISubject {
private ISubject subjectImpl;
public SubjectProxy(ISubject subjectImpl) {
this.subjectImpl = subjectImpl;
}
@Override
public void request() {
System.out.println("some before advice");
subjectImpl.request();
System.out.println("some after advice");
}
}
/**
*
* @author zhangsh
*
*/
public class Client {
public static void main(String[] args) {
ISubject subjcet = new SubjectProxy(new SubjectImpl());
subjcet.request();
}
}
如上,代理实例。
动态代理——JDK动态代理
但是我们通常会有n个对象需要加入同样的advice(比如,监控逻辑,安全校验逻辑),如果我们使用这种方式,必须要为n个对象创建n个代理类。这样太麻烦了,大量重复工作。
使用动态代理,无需写代理类,运行时自动生成某个接口的代理。并在同一个的InvocationHandler中加入定制的Advice。
/**
*
* @author zhangsh
*
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object targetObject;
public MyInvocationHandler(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MyAdvice.beforeAdvice();
Object result = method.invoke(targetObject, args);
MyAdvice.afterAdvice();
return result;
}
}
/**
*
* @author zhangsh
*
*/
public class Client {
public static void main(String[] args) {
// ISubject subjcet = new SubjectProxy(new SubjectImpl());
//
// subjcet.request();
ISubjectA subjectA = (ISubjectA) Proxy.newProxyInstance(ISubjectA.class.getClassLoader(),
new Class[] { ISubjectA.class }, new MyInvocationHandler(new SubjectAImpl()));
ISubjectB subject = (ISubjectB) Proxy.newProxyInstance(ISubjectB.class.getClassLoader(),
new Class[] { ISubjectB.class }, new MyInvocationHandler(new SubjectBImpl()));
// .........
subjectA.request();
subjectB.request();
}
}
动态代理针对接口做代理,如果某个对象并没有实现任何接口。则无法使用JDK动态代理。
动态代理——CGLIB (code generation library)
为了解决上述问题,我们可以使用cglib,cglib可以代理非接口实现的目标对象,也可以像JDK动态代理那样为接口实现类做动态代理。
SpringAOP在发现targetObject 没有实现任何接口时,自动使用CGLIB技术,动态字节码生成,完成代理。
cglib通过动态生成字节码:继承目标对象,通过override目标对象原有方法,实现advice的织入。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
* @author zhangsh
*
*/
public class MyMethodInterceptor implements MethodInterceptor {
/**
* All generated proxied methods call this method instead of the original
* method. The original method may either be invoked by normal reflection
* using the Method object, or by using the MethodProxy (faster).
*
* @param obj
* "this", the enhanced object
* @param method
* intercepted Method
* @param args
* argument array; primitive types are wrapped
* @param proxy
* used to invoke super (non-intercepted method); may be called
* as many times as needed
* @throws Throwable
* any exception may be thrown; if so, super method will not be
* invoked
* @return any value compatible with the signature of the proxied method.
* Method returning void will ignore this value.
* @see MethodProxy
*/
@Override
public Object intercept(Object enhancedOobject, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("Before invoke " + method);
Object result = methodProxy.invokeSuper(enhancedOobject, args);
System.out.println("After invoke" + method);
return result;
}
}
/**
*
* @author zhangsh
*
*/
public class NonInterfaceObjectA {
public void request() {
System.out.println("request NonInterfaceObjectA");
}
}
/**
*
* @author zhangsh
*
*/
public class CglibClient {
public static void main(String[] args) {
MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
Enhancer enhancerA = new Enhancer();
enhancerA.setSuperclass(NonInterfaceObjectA.class);
enhancerA.setCallback(myMethodInterceptor);
NonInterfaceObjectA nonInterfaceObjectA = (NonInterfaceObjectA) enhancerA.create();
Enhancer enhancerB = new Enhancer();
enhancerB.setSuperclass(NonInterfaceObjectB.class);
enhancerB.setCallback(myMethodInterceptor);
NonInterfaceObjectB nonInterfaceObjectB = (NonInterfaceObjectB) enhancerB.create();
nonInterfaceObjectA.request();
System.out.println("----------------------------------");
nonInterfaceObjectB.request();
}
}
CGLIB不足是无法对final方法进行override织入切面逻辑。
隐患注意
- 获取Target,常见proceedingJoinPoint.getTarget
在一个joinpoint做了多次advisor,那么target的获取会出问题,比如的方法既要使用SpringCache注解、hystrix注解….等超过一个的注解:
@SuppressWarnings("unchecked")
public <T> T getUltimateTargetObject(Object candidate) {
Assert.notNull(candidate, "Candidate must not be null");
try {
if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) {
return (T) getUltimateTargetObject(((Advised) candidate).getTargetSource().getTarget());
}
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to unwrap proxied object", ex);
}
return (T) candidate;
}
- 获取方法参数,常见proceedingJoinPoint.getArgs(),需要仔细考虑是否需要defensive Copy Of Args,以防止引用的参数对象(引用类型)变化