0x09.动态代理和Spring AOP原理简介

[TOC]

动态代理

JDK的动态代理是通过实现目标类的接口来创建代理类,借助里式替换原则通过聚合目标类,在接口方法内部委托目标类的接口方法来达到控制对目标方法的访问的目的。

CGLIB则是通过继承来实现代理,具体逻辑是继承目标类创建一个子类,然后重写目标方法,在内部调用父类方法来达到代理的目的。

CGLIB示例

  • 目标类:
public class MyClass {
    public void method() {
        System.out.println("MyClass.method()");
    }
}
  • Testcase
package aop.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class Main {

    @Test
    public void testCGLIB() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        enhancer.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
                                                                                 throws Throwable {
                System.out.println("before");
                System.out.println("method Name:" + method.getName());
                // 调用父类方法来完成实际业务逻辑
                proxy.invokeSuper(target, args);
                System.out.println("after");
                return null;
            }
        });
        MyClass my = (MyClass) enhancer.create();
        my.method();
    }

    
}

JDK动态代理示例

  • 实现接口的目标类
public interface MyInterface {
    void method();

}

public class MyClassWithInterface implements MyInterface {
    @Override
    public void method() {
        System.out.println("MyClassWithInterface.method()");
    }
}

  • TestCase
    @Test
    public void testJDKProxy() {
        final MyClassWithInterface target = new MyClassWithInterface();
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("before");
                        // 实际的业务逻辑还是委托给目标类的
                        method.invoke(target, args);
                        System.out.println("after");
                        return null;
                    }
                });
        proxy.method();
    }

Spring AOP

Spring AOP是基于动态代理的,代理方式包括以上两种,所以只能拦截方法,且不能拦截未实现接口的final class。

AOP生成代理的入口

在Spring中,bean的创建是交给IOC容器的,从上面动态代理的使用来看,基于接口的JDK代理的代理对象的生成是需要持有目标对象的。AOP是基于BeanPostProcessor在createBean逻辑中的回调,涉及的主要后处理器为org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator,调用时机是在目标bean实例化之后,执行initializeBean()初始化内部中执行postProcessAfterInitialization()回调。

调用栈为:doCreateBean()->initializeBean()->applyBeanPostProcessorsAfterInitialization()->org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization()->wrapIfNecessary()->createProxy.

  • wrapIfNecessary

开启了AOP自动代理之后,所有bean的创建都会进入这一步判断是否需要wrap,因为BeanPostProcessor是全局的。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice. // 判断当前的Bean是否有相关的切面
        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;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

判断Bean是否需要代理

是否需要代理的的依据就是wrapIfNecessary方法中的getAdvicesAndAdvisorsForBean(),通过检查本bean是否有关联切面来判断是否需要代理。判断切面关联的逻辑:

    protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
        List advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

重点在于查找和当前bean相关的aspect,如何查找的?

    protected List findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        // 内部逻辑是检查所有注册的Aspect bean,取到其中的Advice定义,封装到Advisor中(InstantiationModelAwarePointcutAdvisor)
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }

findCandidateAdvisors返回所有备选的advisor,下一步进行筛选:findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),最后进行其他处理,返回合格的advisor,继续下一步的代理创建。

生成代理

代理对象的生成入口Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));,详细生成过程是通过ProxyFactory工厂对象生成。

protected Object createProxy(
            Class beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }

        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        return proxyFactory.getProxy(getProxyClassLoader());
    }

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

    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()) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

具体的生成策略有两种:JdkDynamicAopProxyObjenesisCglibAopProxy,就是前述的两种动态代理方式。

  • cglib
public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }

        try {
            Class rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            Class proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class[] additionalInterfaces = rootClass.getInterfaces();
                for (Class additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);

            // Configure 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 UndeclaredThrowableStrategy(UndeclaredThrowableException.class));

            Callback[] callbacks = getCallbacks(rootClass);
            Class[] types = new Class[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Exception ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }
  • jdk
    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);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

你可能感兴趣的:(0x09.动态代理和Spring AOP原理简介)