Spring AOP 创建代理的源码解析

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Spring AOP 创建代理的源码解析

前言

在上篇文章   中已经获取到了 bean 的对应增强器,之后,就可以创建对应的代理了, Spring AOP 底层使用的是 JDK 动态代理 CGLIB 的代理,在什么情况下使用 JDK动态代理,什么时候使用 CGLIB 代理呢,下面通过源码来看一下.


// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //......
    // 获取的增强器
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    //............
    return bean;
}

创建代理 createProxy


protected Object createProxy(Class? beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    // ....
    ProxyFactory proxyFactory = new ProxyFactory();
    //复制当前类的一些属性
    proxyFactory.copyFrom(this);
    // 如果在配置文件中配置的aop标签的属性proxy-target-class为false,
    if (!proxyFactory.isProxyTargetClass()) {
        // 是否需要代理当前类而不是代理接口,根据preserveTargetClass属性来判断Boolean.TRUE.equals(bd.getAttribute("preserveTargetClass")
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 如果代理的是接口,则添加代理接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 对增强器进行包装,有些增强是通过拦截器等方式来实现的,所以这里统一封装为 Advisor 进行处理
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 加入增强器
    proxyFactory.addAdvisors(advisors);
    // 设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    // 用户自定义代理
    customizeProxyFactory(proxyFactory);
    // 该属性用来控制代理工厂被配置以后,是否还允许修改通知,默认为false
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 创建代理
    return proxyFactory.getProxy(getProxyClassLoader());
}

// 添加接口代理
protected void evaluateProxyInterfaces(Class? beanClass, ProxyFactory proxyFactory) {
    Class?[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    //....
    if (hasReasonableProxyInterface) {
        for (Class? ifc : targetInterfaces) {
            proxyFactory.addInterface(ifc);
        }
    }
    else {
        proxyFactory.setProxyTargetClass(true);
    }
}

封装增强,在Spring中,有些增强是通过拦截器来实现的,所以这里统一封装为 Advisor 进行处理,对应方法 buildAdvisors():


protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
    //解析所有的 InterceptorName
    Advisor[] commonInterceptors = resolveInterceptorNames();

    ListObject allInterceptors = new ArrayList();
    if (specificInterceptors != null) {
        // 添加参数传进来的,即我们自定义的增强
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors.length  0) {
            // 添加拦截器
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    //把拦截器包装为Advisor
    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i  allInterceptors.size(); i++) {
        // wrap包装
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

//wrap包装
// 仅仅对 Advisor 和 Advice进行包装
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    // 如果本来就是 Advisor,则直接返回
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    // 类型不正确,异常
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
        // MethodInterceptor 类型使用 DefaultPointcutAdvisor 封装
        return new DefaultPointcutAdvisor(advice);
    }
    // 如果存在 Advisor 的适配器,也需要包装
    for (AdvisorAdapter adapter : this.adapters) {
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

创建代理getProxy


return proxyFactory.getProxy(getProxyClassLoader());

public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

createAopProxy():

在这里会判断代理创建的方式,是使用 JDK 的动态代理还是 CGLIB 的代理。


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //这里初步判断代理的创建方式,如果不满足则直接使用 JDK 动态代理,如果满足条件,则进一步在判断是否使用 JKD 动态代理还是 CGLIB 代理
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class? targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("......");
        }
        // 如果代理的是接口或者设置代理的类就是当前类,则使用 JDK 动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 否则使用 CGLIB 代理
        return new ObjenesisCglibAopProxy(config);
    }
    // 条件不满足CGBLIB的方式直接使用JDK动态代理
    else {
        return new JdkDynamicAopProxy(config);
    }
}

这里的 if 条件有三个:

  • `config.isOptimize()` : 用来控制通过 CGLIB 创建的代理是否使用激进的优化策略,目前仅用于 CGLIB 代理
  • `config.isProxyTargetClass()` :  在  中了解到,我们可以强制 Spring 完全使用 CGLIB 进行代理,只要在配置文件配置 `proxy-target-class` 属性为true即可,如:`aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/`,如果配置个该属性,则会使用 CGLIB 来创建代理
  • `hasNoUserSuppliedProxyInterfaces(config)` : 是否存在代理接口,如果不存在代理接口,则使用 CGLIB 进行代理
  • config.isProxyTargetClass() :  在  中了解到,我们可以强制 Spring 完全使用 CGLIB 进行代理,只要在配置文件配置 proxy-target-class 属性为true即可,如: aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/,如果配置个该属性,则会使用 CGLIB 来创建代理

    如果这三个条件有一个满足,则会再进一次判断,需要代理的类是否是接口或者是否设置的就是代理当前类,如果是,则还是会使用 JDK 动态代理,否则的话才会使用 CGLIB 代理。

    1.如果代理类实现了接口,则Spring默认使用 JDK 动态代理,但可以设置强制使用 CGLIB 代理 2.JDK 动态代理只能代理接口而不能代理类 3.CGLIB 代理类,通过继承的方式,为目标类生成子类,并重写方法来实现代理,它不能代理final的类或方法 4.关于 JDK 动态代理和 CGLIB 代理的使用方式可以参考 

    接下来看下 JDK 动态代理和 CGLIB 代理的创建过程:

    JDK 动态代理

    
    return new JdkDynamicAopProxy(config);
    
    // JdkDynamicAopProxy.java
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
        this.advised = config;
    }
    

    通过 JDK 动态代理来获取代理的方法 getProxy():

    
    public Object getProxy(ClassLoader classLoader) {
        // 获取代理类的接口
        Class?[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        // 处理 equals , hashcode 方法
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // 创建代理
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    

    可以看到, Spring 使用 JDK 创建代理和我们使用的 JDK 来创建代理是没有区别的,都是使用 Proxy.newProxyInstance 的方式来创建;我们知道 JDK 动态代理有个 invoke 方法,用来执行目标方法,而 JdkDynamicAopProxy 实现了 InvocationHandler 接口,所有它也会重写该方法,在该方法中植入增强:

    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
        // 目标类
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;
    
        try {
            // 如果接口没有定义 equals 方法且当前方法是 equals 方法,则不会增强,直接返回
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // 如果接口没有定义 hashCode方法且当前方法是 hashCode方法,则不会增强,直接返回
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // 如果方法所在的类和Advised是同一个类或者是父类子类关系,则直接执行
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
            // 返回值
            Object retVal;
    
            // 这里对应的是expose-proxy属性的应用,把代理暴露处理
            // 目标方法内部的自我调用将无法实施切面中的增强,所以在这里需要把代理暴露出去
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
    
            target = targetSource.getTarget();
            Class? targetClass = (target != null ? target.getClass() : null);
    
            // 获取该方法的拦截器
            ListObject chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
            //如果方法的拦截器为空,则直接执行目标方法,避免创建 MethodInvocation 对象
            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                // 执行目标方法:method.invoke(target, args)
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // 把所有的拦截器封装在ReflectiveMethodInvocation中,以便于链式调用 
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 执行拦截器链
                retVal = invocation.proceed();
            }
            // ..........
            return retVal;
        }
        finally {
          // .            
        }
    }
    

    在执行拦截器方法 proceed 中执行增强方法,比如前置增强在方法之前执行,后置增强在方法之后执行, proceed 方法如下:

    
    public Object proceed() throws Throwable {
        //当执行完所有增强方法后执行目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            // method.invoke(target, args)
            return invokeJoinpoint();
        }
         // 获取下一个要执行的拦截器
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // 动态匹配
            InterceptorAndDynamicMethodMatcher dm = interceptorOrInterceptionAdvice;
            Class? targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            // 如果能够匹配,则执行拦截器的方法,
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                // 比如 @After @Before 对应的增强器(拦截器)的方法
                // 比如 @After 对应的增强器 AspectJAfterAdvice 的invoke方法为:MethodInvocation.proceed();
                return dm.interceptor.invoke(this);
            }
            else {
                // 如果动态匹配失败,则跳过该拦截器,执行下一个拦截器
                return proceed();
            }
        }
        else {
            // 普通拦截器,直接调用
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    

    在该方法中完成了增强的植入,主要逻辑就是,每个方法都会有一个拦截器链,在 AOP 中我们称之为增强,然后循环执行每个拦截器链,当执行完所有的拦截器后,才会执行目标方法。比如 @After 对应的增强器 AspectJAfterAdvice @Around对应的增强器 AspectJAroundAdvice等。

    以上就是 Spring 通过 JDK 动态代理来实现 AOP 的一个过程。

    CGLIB 代理

    ObjenesisCglibAopProxy 继承于 CglibAopProxy

    
    return new ObjenesisCglibAopProxy(config)
    
    public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
        this.advised = config;
        this.advisedDispatcher = new AdvisedDispatcher(this.advised);
    }
    

    CglibAopProxy getProxy 方法如下:

    
    public Object getProxy(ClassLoader classLoader) {
        // 代理的目标类
        Class? rootClass = this.advised.getTargetClass();
        Class? proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class?[] additionalInterfaces = rootClass.getInterfaces();
            for (Class? additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }
        // 创建并配置 CGLIB Enhancer
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
    
        // 设置拦截器
        Callback[] callbacks = getCallbacks(rootClass);
        Class?[] types = new Class?[callbacks.length];
        for (int x = 0; x  types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
    
        //生成代理类和创建代理
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    
    // 生成代理类和创建代理
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
        enhancer.setInterceptDuringConstruction(false);
        enhancer.setCallbacks(callbacks);
        return (this.constructorArgs != null && this.constructorArgTypes != null ?
                enhancer.create(this.constructorArgTypes, this.constructorArgs) :
                enhancer.create());
    }
    

    从上述的方法可知,Sping 使用 CGLIB 来创建代理类和代理对象和我们使用的一样,都是使用 Enhancer.create() 来创建,这里主要的是设置拦截器,通过 getCallbacks () 方法来实现的,如下:

    
    private Callback[] getCallbacks(Class? rootClass) throws Exception {
        //expose-proxy 属性
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
    
        // 将拦截器封装在 DynamicAdvisedInterceptor 中
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
        //暴露代理
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = (isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
        }
        else {
            targetInterceptor = (isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
        }
        // 将拦截器 aopInterceptor 进入到 Callback 中 
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };
        // ..............
        return callbacks;
    }
    

    我们知道使用 CGLIB 来实现代理功能的时候,当代理执行的时候,会调用 intercept 方法,和 JKD 动态代理 invoke 方法类似;Spring 中 CGLIB intercept 方法如下,该方法在 DynamicAdvisedInterceptor 中,从上面的代理知道,使用它来封装拦截器,它是 CglibAopProxy 的一个子类:

    
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){
        Object oldProxy = null;
        boolean setProxyContext = false;
        Object target = null;
        // 目标类
        TargetSource targetSource = this.advised.getTargetSource();
        // 处理 expose-proxy 属性,暴露代理
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        target = targetSource.getTarget();
        Class? targetClass = (target != null ? target.getClass() : null);
    
        // 获取拦截器链
        ListObject chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
        // 返回值
        Object retVal;
    
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 如果拦截器为空则直接执行目标方法
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            //封装拦截器链并执行
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        // 处理返回值类型
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
        // .....................
    }
    

    CGLIB 使用 CglibMethodInvocation 来封装拦截器链,它是 CglibAopProxy 的一个内部类:

    
    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
    
        @Nullable
        private final MethodProxy methodProxy;
    
        public CglibMethodInvocation(Object proxy, Object target, Method method,Object[] arguments, Class? targetClass, ListObject interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
    
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
    
            this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
                    method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
                    !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
                    methodProxy : null);
        }
    
        // proceed 方法会调用该方法来执行
        @Override
        protected Object invokeJoinpoint() throws Throwable {
            if (this.methodProxy != null) {
                return this.methodProxy.invoke(this.target, this.arguments);
            }
            else {
                return super.invokeJoinpoint();
            }
        }
    }
    

    当调用 proceed 方法时,和 JDK 的处理是一样的,只不过当执行完所有的拦截器后,执行目标方法调用的是 CglibMethodInvocation  的 invokeJoinpoint 来执行而已;

    因为 CglibMethodInvocation 继承于 ReflectiveMethodInvocation ,而 JDK 使用的就是 ReflectiveMethodInvocation 来执行的, ReflectiveMethodInvocation invokeJoinpoint 方法为 : method.invoke(target, args)

    以上就是 Spring  使用 JDK 动态代理和 CGLIB 代理来实现 AOP 的原理。

    原文始发于微信公众号(Java技术大杂烩):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Spring AOP 创建代理的源码解析


     上一篇
    Spring AOP 注解方式源码解析 Spring AOP 注解方式源码解析
    前言在上篇文章  中,知道了 Sprig AOP 的一个详细用法,现在的看看Spring 中是如何实现的。 aspectj-autoproxy我们知道,要想使用 Spring AOP ,必须首先在配置文件中添加该配置项 aop:aspec
    2021-04-05
    下一篇 
    Spring 中 bean 注册的源码解析 Spring 中 bean 注册的源码解析
    前言所谓 bean 的注册,就是把在配置文件中配置的  bean 节点加载配内存中,供后续使用。 bean的注册主要分为两个阶段,一个是准备阶段,就是对配置文件进行解析,把配置文件加载到内存中,以  Document 的形式存放;第二个阶段
    2021-04-05