0
点赞
收藏
分享

微信扫一扫

[Spring]Spring AOP创建动态代理的过程

扒皮狼 2021-09-25 阅读 52

Spring AOP的大致流程

我们在之前的2章中,知晓了Spring AOPBeanPostProcessor的几个关键接口做了介入,分为几个关键点:

  1. 将切面类进行解析成advisors,其中包括解析XML和被@Aspect注解标注的Java切面类.
  2. 在初始化Bean的阶段,将advisors对当前Bean进行筛选,获取到当前Bean匹配的advisors.
  3. 进行动态代理类的创建.

创建动态代理的入口:wrapIfNecessary

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的TargetSource被解析过了
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 如果Bean为advisedBeans,也不需要被代理
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // isInfrastructureClass和shouldSkip的作用:
    // 识别切面类,加载切面类成advisors
    // 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 返回匹配当前Bean的所有Advice、Advisor、Interceptor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息
        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;
}

创建动态代理:createProxy

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 如果beanFactory是ConfigurableListableBeanFactory的类型,暴露目标类
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 创建一个ProxyFactory,当前ProxyCreator在创建代理时,将需要用到的字段赋值到ProxyFactory中去
    ProxyFactory proxyFactory = new ProxyFactory();
    // 将当前的AnnotationAwareAspectJAutoProxyCreator对象的属性赋值给ProxyFactory对象
    // 加载一些ProxyConfig
    proxyFactory.copyFrom(this);
    // 处理proxyTargetClass属性
    // 如果希望使用CGLIB进行代理,配置proxyTargetClass为true
    if (!proxyFactory.isProxyTargetClass()) {
        // 检查相应BeanDefinition的“ preserveTargetClass”属性
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 1. 有接口的,调用一次或者多次:proxyFactory.addInterface(ifc);
            // 2. 没有接口的,调用: proxyFactory.setProxyTargetClass(true);
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 这个方法主要是对前面传递进来的横切逻辑实例进行包装
    // specificInterceptors中有Advice和Interceptor,它们都会被包装成Advisor
    // 调用的先后顺序,通过方法中的applyCommonInterceptorsFirst参数进行设置
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    // 扩展实现,子类可以定制proxyFactory
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // 设置preFiltered的属性值,默认为false.子类:AbstractAdvisorAutoProxyCreator修改为true
    // preFiltered字段的意思是:是否为特定目标类筛选Advisor
    // 该字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取所有的Advisors
    // CglibAopProxy和JdkDynamicAopProxy都会调用此方法,然后递归执行所有的advisor
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}

getProxy: 根据当前bean选择JDK或者CGLIB动态代理

  • org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
    // 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy
    // 分别用于JDK和CGLIB代理类的生成,其getProxy方法则用于获取具体的代理对象
    return createAopProxy().getProxy(classLoader);
}
  • org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
    // 激活AdvisedSupportListener监听器
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}
  • org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
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.");
        }
        // 如果要代理的类本身就是接口
        // 或者它已经是JDK的代理类(Proxy子类)
        // 使用JDK动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 使用CGLIB动态代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        // 接口->JDK动态代理
        return new JdkDynamicAopProxy(config);
    }
}

工厂模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy

由于篇幅的原因,我选择讲解JdkDynamicAopProxy这种模式生成代理的源码解析.

  • org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
    }
    // 获取完整的代理接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // JdkDynamicAopProxy本身实现了InvocationHandler接口
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
  • org.springframework.aop.framework.JdkDynamicAopProxy#invoke
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        // equals方法不需要代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashcode方法不需要代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;
        // 是否暴露代理引用
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        // 获取目标类
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // Get the interception chain for this method.
        // 获取方法的拦截链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        // 如果该方法上没有匹配的拦截器,直接反射调用Method.invoke(target,args)
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // We need to create a method invocation...
            // 创建ReflectiveMethodInvocation
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            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()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

代理类执行链路

  • org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
    // 如果拦截器执行完了,则执行连接点
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }
    // 从0开始执行,每次递归进来都会+1
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        // 动态匹配:运行时参数是否满足匹配条件
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            // 动态匹配失败,进入下一个拦截器
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        // 执行当前拦截器
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}
执行流程图

总结

  • 1. 生成代理类通过工厂模式进行生成,实现接口默认使用JDK动态代理,否则使用CGLIB
  • 2. Spring AOP通过后置处理器的postProcessAfterInitialization方法调用wrapIfNessary对Bean进行代理并替换.
  • 3. 代理类执行拦截链通过chain进行递归proceed来执行每个通知的方法
举报

相关推荐

0 条评论