ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Spring AOP 创建代理的源码解析

2021-01-27 23:05:52  阅读:108  来源: 互联网

标签:拦截器 return Spring Object 代理 源码 AOP new method


Spring AOP 创建代理的源码解析

TSMYK Java技术编程

前言

在上篇文章 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();

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

创建代理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);
    }
}
  1. 这里的 if 条件有三个:

config.isOptimize() : 用来控制通过 CGLIB 创建的代理是否使用激进的优化策略,目前仅用于 CGLIB 代理

  1. config.isProxyTargetClass() : 在 Spring AOP 注解方式源码解析 中了解到,我们可以强制 Spring 完全使用 CGLIB 进行代理,只要在配置文件配置 proxy-target-class 属性为true即可,如:<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>,如果配置个该属性,则会使用 CGLIB 来创建代理

    1. hasNoUserSuppliedProxyInterfaces(config) : 是否存在代理接口,如果不存在代理接口,则使用 CGLIB 进行代理

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

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

接下来看下 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);

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

在执行拦截器方法 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).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());
}

从上述的方法可知,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);

    // 获取拦截器链
    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 使用 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, 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();
        }
    }
}

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

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

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

标签:拦截器,return,Spring,Object,代理,源码,AOP,new,method
来源: https://blog.51cto.com/15077536/2608544

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有