继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

spring aop & jdk的动态代理

SEVEN_SONG
关注TA
已关注
手记 13
粉丝 5
获赞 27

知识回顾

在文章初识AOP中,了解到为什么要用代理,静态代理和动态代理的区别,在JDK的动态代理中讲到JDK的动态代理是如何实现的,有什么优缺点,CGLIB中动态代理中我们又说明了CGLIB如何实现动态代理,和JDK动态代理有什么区别,本篇将继续聊下Spring中的AOP是如何结合JDK的动态代理和CGLIB的动态代理来实现的

AOP术语

  1. 通知(Advice) 通知定义了切面是什么以及何时使用,描述了切面要完成的工作(比如权限、日志、事物),通知还解决了何时执行这个工作的问题,在方法前、后、还是抛出异常时,通知包含了5中类型,如下:
    Before:方法调用前调用通知
    After:在方法完成之后调用通知,不论方法执行是否成功
    After-returing: 在方法成功执行之后调用通知
    After-throwing:在方法抛出异常后调用通知
    Around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

  2. 连接点(Joinpint)连接点是应用执行过程中能够插入切面的一个点,这个点可以使调用方法时、抛出异常时、甚至是修改一个自短时。切面代码可以利用这些点插入到应用的的正常流程之中,并添加新的行为
  3. 切点(Pointcut)通知定义了切面的 “什么”和“何时”,切点是定义了“何处”。切点的定义会匹配通知所要织入的一个或多个连接点。
  4. 切面(Aspect)切面是切点和通知的结合,定义了 什么、在何时、何处完成其功能
  5. 引入(Introduction)引入运行我们在不修改类的源码的情况下,向现有的类添加新的方法和属性
  6. 织入(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");

    }
}

总结

  1. Spring AOP 是根据一些配置和代理类是否实现接口来选择使用JDK的动态代理还是使用CGLIB的动态代理的
  2. Spring 中的每个通知,前置通知、后置通知、环绕通知等都最终会根据AdvisorAdapter来获取一个MethodInterceptor,然后根据得到的MethodInterceptor集合,最终创建一个MethodInvocation(ReflectiveMethodInvocation),然后通过ReflectiveMethodInvocation来执行每个拦截器,其实是使用了责任链的模式来调用的,和Servet中的Filter是一样的
  3. Spring的AOP其实和容器是没有关系的,也就是是脱离IOC也是可以正常使用AOP的,只不过结合IOC更加完美方便

微信公众号:宋坤明
下面的是我的公众号二维码图片,欢迎关注。
图注:宋坤明公众号

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP