知识回顾
在文章初识AOP中,了解到为什么要用代理,静态代理和动态代理的区别,在JDK的动态代理中讲到JDK的动态代理是如何实现的,有什么优缺点,CGLIB中动态代理中我们又说明了CGLIB如何实现动态代理,和JDK动态代理有什么区别,本篇将继续聊下Spring中的AOP是如何结合JDK的动态代理和CGLIB的动态代理来实现的
AOP术语
-
通知(Advice) 通知定义了切面是什么以及何时使用,描述了切面要完成的工作(比如权限、日志、事物),通知还解决了何时执行这个工作的问题,在方法前、后、还是抛出异常时,通知包含了5中类型,如下:
Before:方法调用前调用通知
After:在方法完成之后调用通知,不论方法执行是否成功
After-returing: 在方法成功执行之后调用通知
After-throwing:在方法抛出异常后调用通知
Around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为 - 连接点(Joinpint)连接点是应用执行过程中能够插入切面的一个点,这个点可以使调用方法时、抛出异常时、甚至是修改一个自短时。切面代码可以利用这些点插入到应用的的正常流程之中,并添加新的行为
- 切点(Pointcut)通知定义了切面的 “什么”和“何时”,切点是定义了“何处”。切点的定义会匹配通知所要织入的一个或多个连接点。
- 切面(Aspect)切面是切点和通知的结合,定义了 什么、在何时、何处完成其功能
- 引入(Introduction)引入运行我们在不修改类的源码的情况下,向现有的类添加新的方法和属性
- 织入(Weaving)织入是吧切面应用到目标对象创建代理对象的过程,切面在指定的连接点被织入到目标对象中
Spring AOP 示例
前提:先引入spring-context的jar包
同样的例子 定义一个IHello的接口和一个Hello的实现类如下
package seven.com.seven.aop;
public interface IHello {
void say();
}
package seven.com.seven.aop;
public class Hello implements IHello {
@Override
public void say() {
System.out.println("hello word");
}
}
定义一个前置通知,一个后置通知,一个环绕通知,如下
package seven.com.seven.aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("------------------before------------------");
}
}
package seven.com.seven.aop;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("------------------after------------------");
}
}
package seven.com.seven.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class SurroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("------------------surround before---------------------");
Object result = invocation.proceed();
System.out.println("------------------surround after----------------------");
return result;
}
}
spring aop 实现动态代理
package seven.com.seven.aop;
import org.springframework.aop.framework.ProxyFactory;
public class DynamicSpringProxy {
private Object target;
public Object getProxy(Object target) {
/**
* 通过此语句可以把动态生成的class文件保存到磁盘,然后通过 反编译工具得到代码
*/
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
this.target = target;
ProxyFactory factory = new ProxyFactory(target);
factory.addAdvice(new BeforeAdvice());
factory.addAdvice(new AfterAdvice());
factory.addAdvice(new SurroundAdvice());
return factory.getProxy();
}
}
package seven.com;
import seven.com.seven.aop.*;
public class App {
public static void main(String[] args) {
Hello hello = new Hello();
IHello proxy = (IHello) new DynamicSpringProxy().getProxy(hello);
proxy.say();
}
}
运行结果
------------------before------------------
------------------surround before------------------
hello word
------------------surround after------------------
------------------after------------------
分析
我们看到拦截已经生效,那Spring AOP是使用JDK的动态代理还是CGLib的动态代理呢?我们打开源码可以看下DefaultAopProxyFactory这个类,选择AopProxyFactory的过程如下
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
//默认是使用JDK的动态代理,如果想使用CGLib的动态代理,可以吧proxyTargetClass设置为True
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
JdkDynamicAopProxy
选择的JDK的动态代理,其实就是创建JdkDynamicAopProxy对象,JdkDynamicAopProxy实现了InvocationHandler接口(JDK动态代理要求的,前面文章提到过),最终会执行invoke方法,代码如下
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
/**
* 这里其实就是我们之前文章中讲到的JDK的动态代理生成机制,调用了Proxy.newProxyInstance的静态方法
* 最后一个参数传入的是this,所以这个类是继承自InvocationHandler的,最终执行方法时也是会执行到invoke方法
*/
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
/**
* 最终方法会执行到这里,然后会创建ReflectiveMethodInvocation,使用责任链模式,开始执行拦截器链
* 每个通知最终都会创建一个对应的拦截器,比如BeforeAdvice对应MethodBeforeAdviceInterceptor
* AfterAdvice对应AfterReturningAdviceInterceptor
* SurroundAdvice本身就是一个拦截器
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
/** 这里是根据上面添加的通知,创建对应的拦截器,详细代码可以参考DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法
* 每个通知(Advice)会对应一个AdvisorAdapter,根据AdvisorAdapter又可以获取一个MethodInterceptor,具体可以参考DefaultAdvisorAdapterRegistry类
*/
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
ReflectiveMethodInvocation
ReflectiveMethodInvocation是用来实现责任链模式的,就是利用我们得到的拦截器列表创建ReflectiveMethodInvocation对象,然后执行ReflectiveMethodInvocation的proceed方法,其实就是遍历执行拦截器的invoke方法,同时把ReflectiveMethodInvocation对象本身传入到invoke中,这样执行完拦截器的内容后,又会回到这个ReflectiveMethodInvocation种执行proceed方法,反复如此,知道拦截器全部执行完成,已达到调用链的执行模式,这个责任链模式的调用过程中,不论如何使用拦截器,最终的被代理对象的方法肯定是只会执行一次的,这一点可以根据源码看到
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
Spring 生成的代理类
因为spring aop本就是根据jdk的动态代理来生成代理类的,所以自然和之前讲到的jdk的动态代理生成的模式是一样的,不同点是多实现了几个接口而已,根据上面例子生成的代理类如下
package com.sun.proxy;
public final class $Proxy0 extends Proxy implements IHello, SpringProxy, Advised, DecoratingProxy {
private static Method m1;
private static Method m14;
private static Method m21;
private static Method m25;
private static Method m16;
private static Method m22;
private static Method m4;
private static Method m10;
private static Method m7;
private static Method m8;
private static Method m0;
private static Method m23;
private static Method m19;
private static Method m20;
private static Method m9;
private static Method m2;
private static Method m26;
private static Method m15;
private static Method m27;
private static Method m17;
private static Method m5;
private static Method m6;
private static Method m3;
private static Method m18;
private static Method m11;
private static Method m24;
private static Method m13;
private static Method m12;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
}
public final void addAdvisor(Advisor var1) throws AopConfigException {
super.h.invoke(this, m14, new Object[]{var1});
}
public final boolean isExposeProxy() throws {
return (Boolean)super.h.invoke(this, m21, (Object[])null);
}
public final boolean isProxyTargetClass() throws {
return (Boolean)super.h.invoke(this, m25, (Object[])null);
}
public final void removeAdvisor(int var1) throws AopConfigException {
super.h.invoke(this, m16, new Object[]{var1});
}
public final Class[] getProxiedInterfaces() throws {
return (Class[])super.h.invoke(this, m22, (Object[])null);
}
public final int indexOf(Advisor var1) throws {
return (Integer)super.h.invoke(this, m4, new Object[]{var1});
}
public final TargetSource getTargetSource() throws {
return (TargetSource)super.h.invoke(this, m10, (Object[])null);
}
public final void addAdvice(int var1, Advice var2) throws AopConfigException {
super.h.invoke(this, m7, new Object[]{var1, var2});
}
public final void addAdvice(Advice var1) throws AopConfigException {
super.h.invoke(this, m8, new Object[]{var1});
}
public final int hashCode() throws {
return (Integer)super.h.invoke(this, m0, (Object[])null);
}
public final boolean isInterfaceProxied(Class var1) throws {
return (Boolean)super.h.invoke(this, m23, new Object[]{var1});
}
public final boolean removeAdvice(Advice var1) throws {
return (Boolean)super.h.invoke(this, m19, new Object[]{var1});
}
public final void setExposeProxy(boolean var1) throws {
super.h.invoke(this, m20, new Object[]{var1});
}
public final void setTargetSource(TargetSource var1) throws {
super.h.invoke(this, m9, new Object[]{var1});
}
public final String toString() throws {
return (String)super.h.invoke(this, m2, (Object[])null);
}
public final Class getTargetClass() throws {
return (Class)super.h.invoke(this, m26, (Object[])null);
}
public final void addAdvisor(int var1, Advisor var2) throws AopConfigException {
super.h.invoke(this, m15, new Object[]{var1, var2});
}
public final Class getDecoratedClass() throws {
return (Class)super.h.invoke(this, m27, (Object[])null);
}
public final boolean removeAdvisor(Advisor var1) throws {
return (Boolean)super.h.invoke(this, m17, new Object[]{var1});
}
public final int indexOf(Advice var1) throws {
return (Integer)super.h.invoke(this, m5, new Object[]{var1});
}
public final boolean isFrozen() throws {
return (Boolean)super.h.invoke(this, m6, (Object[])null);
}
public final void say() throws {
super.h.invoke(this, m3, (Object[])null);
}
public final boolean replaceAdvisor(Advisor var1, Advisor var2) throws AopConfigException {
return (Boolean)super.h.invoke(this, m18, new Object[]{var1, var2});
}
public final void setPreFiltered(boolean var1) throws {
super.h.invoke(this, m11, new Object[]{var1});
}
public final String toProxyConfigString() throws {
return (String)super.h.invoke(this, m24, (Object[])null);
}
public final Advisor[] getAdvisors() throws {
return (Advisor[])super.h.invoke(this, m13, (Object[])null);
}
public final boolean isPreFiltered() throws {
return (Boolean)super.h.invoke(this, m12, (Object[])null);
}
static {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m14 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Class.forName("org.springframework.aop.Advisor"));
m21 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isExposeProxy");
m25 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isProxyTargetClass");
m16 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Integer.TYPE);
m22 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getProxiedInterfaces");
m4 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.springframework.aop.Advisor"));
m10 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetSource");
m7 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Integer.TYPE, Class.forName("org.aopalliance.aop.Advice"));
m8 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Class.forName("org.aopalliance.aop.Advice"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m23 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isInterfaceProxied", Class.forName("java.lang.Class"));
m19 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvice", Class.forName("org.aopalliance.aop.Advice"));
m20 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setExposeProxy", Boolean.TYPE);
m9 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setTargetSource", Class.forName("org.springframework.aop.TargetSource"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m26 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetClass");
m15 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Integer.TYPE, Class.forName("org.springframework.aop.Advisor"));
m27 = Class.forName("org.springframework.core.DecoratingProxy").getMethod("getDecoratedClass");
m17 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Class.forName("org.springframework.aop.Advisor"));
m5 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.aopalliance.aop.Advice"));
m6 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isFrozen");
m3 = Class.forName("seven.com.seven.aop.IHello").getMethod("say");
m18 = Class.forName("org.springframework.aop.framework.Advised").getMethod("replaceAdvisor", Class.forName("org.springframework.aop.Advisor"), Class.forName("org.springframework.aop.Advisor"));
m11 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setPreFiltered", Boolean.TYPE);
m24 = Class.forName("org.springframework.aop.framework.Advised").getMethod("toProxyConfigString");
m13 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getAdvisors");
m12 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isPreFiltered");
}
}
总结
- Spring AOP 是根据一些配置和代理类是否实现接口来选择使用JDK的动态代理还是使用CGLIB的动态代理的
- Spring 中的每个通知,前置通知、后置通知、环绕通知等都最终会根据AdvisorAdapter来获取一个MethodInterceptor,然后根据得到的MethodInterceptor集合,最终创建一个MethodInvocation(ReflectiveMethodInvocation),然后通过ReflectiveMethodInvocation来执行每个拦截器,其实是使用了责任链的模式来调用的,和Servet中的Filter是一样的
- Spring的AOP其实和容器是没有关系的,也就是是脱离IOC也是可以正常使用AOP的,只不过结合IOC更加完美方便
微信公众号:宋坤明
下面的是我的公众号二维码图片,欢迎关注。