Source code analysis of Spring AOP creation proxy

Source code analysis of Spring AOP creation proxy

TSMYK Java technology programming

Preface

In the last article Spring AOP annotation method source code analysis has obtained the corresponding enhancer of the bean, after that, the corresponding proxy can be created. The bottom layer of Spring AOP is the JDK dynamic proxy and the CGLIB proxy. Under what circumstances should JDK be used Dynamic proxy, when to use CGLIB proxy, let's take a look at the source code.


// 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;
}

Create proxy 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);
    }
}

Encapsulation enhancements. In Spring, some enhancements are implemented through interceptors, so here are unified encapsulation for Advisor for processing, corresponding to the method buildAdvisors():


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

    List<Object> 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);
}

Create proxy getProxy


return proxyFactory.getProxy(getProxyClassLoader());

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

createAopProxy():

Here it will be judged whether the method of proxy creation is to use the dynamic proxy of JDK or the proxy of 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);
    }
}
  1. There are three if conditions here:

config.isOptimize(): Used to control whether the proxy created by CGLIB uses aggressive optimization strategy, currently only used for CGLIB proxy

  1. config.isProxyTargetClass(): In the source code analysis of Spring AOP annotations, we learned that we can force Spring to use CGLIB for proxying, as long as the proxy-target-class attribute is set to true in the configuration file, such as: <aop:aspectj- autoproxy expose-proxy="true" proxy-target-class="true"/>, if this attribute is configured, CGLIB will be used to create the proxy

    1. hasNoUserSuppliedProxyInterfaces(config): Whether there is a proxy interface, if there is no proxy interface, use CGLIB for proxy

    If one of these three conditions is met, it will be judged again, whether the class that needs to be proxy is an interface or whether it is set to proxy the current class, if it is, then JDK dynamic proxy will be used, otherwise CGLIB proxy will be used .

1. If the proxy class implements the interface, Spring uses JDK dynamic proxy by default, but can be set to force the use of CGLIB proxy
2. JDK dynamic proxy can only proxy interfaces but not classes
3. CGLIB proxy class, through inheritance, is the goal The class generates subclasses and rewrites methods to implement proxying. It cannot proxy final classes or methods
. 4. For the usage of JDK dynamic proxy and CGLIB proxy, please refer to Spring AOP function usage details

Next, look at the creation process of JDK dynamic proxy and CGLIB proxy:

JDK dynamic proxy


return new JdkDynamicAopProxy(config);

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

Get the proxy method getProxy() through JDK dynamic proxy:


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

As you can see, there is no difference between Spring's use of JDK to create a proxy and the JDK we use to create a proxy. Both are created using Proxy.newProxyInstance; we know that JDK dynamic proxy has an invoke method to execute the target method. JdkDynamicAopProxy implements the InvocationHandler interface, so it will also rewrite this method and implant enhancements in this method:


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);

        // 获取该方法的拦截器
        List<Object> 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 {
      // .            
    }
}

The enhancement method is executed in the execution interceptor method proceed. For example, the pre-enhancement is executed before the method and the post-enhancement is executed after the method. The proceed method is as follows:


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);
    }
}

The enhanced implantation is completed in this method. The main logic is that each method will have an interceptor chain, which we call enhancement in AOP, and then execute each interceptor chain in a loop, when all interceptors are executed After that, the target method will be executed. For example, the enhancer AspectJAfterAdvice corresponding to @After, the enhancer AspectJAroundAdvice corresponding to @Around, etc.

The above is a process in which Spring implements AOP through JDK dynamic proxy.

CGLIB agent

ObjenesisCglibAopProxy inherits from CglibAopProxy


return new ObjenesisCglibAopProxy(config)

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

The getProxy method of CglibAopProxy is as follows:


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).isCla***eloadable(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());
}

From the above method, we can see that Sping uses CGLIB to create proxy classes and proxy objects, just like we use. They are created using Enhancer.create(). The main thing here is to set up the interceptor, which is implemented through the getCallbacks () method. as follows:


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;
}

We know that when CGLIB is used to implement the proxy function, when the proxy is executed, the intercept method will be called, which is similar to the invoke method of JKD dynamic proxy; the intercept method of CGLIB in Spring is as follows, the method is in the DynamicAdvisedInterceptor, from the proxy above , Use it to encapsulate the interceptor, it is a subclass of 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);

    // 获取拦截器链
    List<Object> 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 = proce***eturnType(proxy, target, method, retVal);
    return retVal;
    // .....................
}

CGLIB uses CglibMethodInvocation to encapsulate the interceptor chain, which is an internal class of CglibAopProxy:


private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

    @Nullable
    private final MethodProxy methodProxy;

    public CglibMethodInvocation(Object proxy, Object target, Method method,Object[] arguments, Class<?> targetClass, List<Object> 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();
        }
    }
}

When the proceed method is invoked, the processing is the same as that of the JDK, except that after all the interceptors are executed, the execution target method calls the invokeJoinpoint of CglibMethodInvocation to execute it;

Because CglibMethodInvocation inherits from ReflectiveMethodInvocation, and JDK uses ReflectiveMethodInvocation to execute, the invokeJoinpoint method of ReflectiveMethodInvocation is: method.invoke(target, args)

The above is the principle that Spring uses JDK dynamic proxy and CGLIB proxy to implement AOP.

Guess you like

Origin blog.51cto.com/15077536/2608544