Spring 源码解析 | Aop 源码实现(一)

 2023-01-27
原文作者:心城以北 原文地址:https://juejin.cn/post/7017463197514858526

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本次我们一起来聊一下 Spring Aop 的原理。本文主要是通过一个简单的 Aop 案例,然后结合 Spring 的源码进行分析, Spring Aop 介入时机; Spring Aop 初始化等。 环境介绍:

  • JDK 17
  • Spring 6.0.0-SNAPSHOT

案例介绍

我们在业务中可能用到 Redis 作为分布式锁,如果我们手动去 lock, unLock。 这样做的缺点就是代码量比较大,结合我们当前的 Aop 原理背景, 我们可以对我们业务开发中的 Lock 做一个简单的封装。

案例代码

代码如下所示:

    @Component
    @Aspect
    public class DistributedLockAspect {
    
    	private static final Logger logger = LoggerFactory.getLogger(DistributedLockAspect.class);
    
    
    	@Pointcut("@annotation(com.summer.test.distributedlock.DistributedLock)")
    	public void distributedLockPointCut() {
    		// distributedLockPointCut
    	}
    
    	@Around("distributedLockPointCut()")
    	public Object distributedLockAround(ProceedingJoinPoint pjp) throws Throwable {
    		Method method = ((MethodSignature) pjp.getSignature()).getMethod();
    		DistributedLock ub = method.getAnnotation(DistributedLock.class);
    		String lockKey = lockKey(ub.key(), pjp);
    		long timeOut = ub.timeOut();
    		logger.debug("Start Redis Distributed Lock, Lock key:{}", lockKey);
    		try {
    			// todo redis lock
    			Object result = pjp.proceed();
    			logger.debug("End Redis Distributed Lock, Lock key:{}", lockKey);
    			return result;
    		} catch (Throwable ex) {
    			logger.warn("Error Redis Distributed Lock, Lock key:{}", lockKey);
    			throw ex;
    		}
    	}
    
    	private String lockKey(String key, ProceedingJoinPoint joinPoint) {
    		SpelExpressionParser parser = new SpelExpressionParser();
    		DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
    		// 通过joinPoint获取被注解方法
    		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    		Method method = methodSignature.getMethod();
    		// 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组
    		String[] paramNames = nameDiscoverer.getParameterNames(method);
    		// 解析过后的Spring表达式对象
    		Expression expression = parser.parseExpression(key);
    		// spring的表达式上下文对象
    		EvaluationContext context = new StandardEvaluationContext();
    		// 通过joinPoint获取被注解方法的形参
    		Object[] args = joinPoint.getArgs();
    		// 给上下文赋值
    		if (paramNames != null) {
    			for (int i = 0; i < args.length; i++) {
    				context.setVariable(paramNames[i], args[i]);
    			}
    		}
    		// 表达式从上下文中计算出实际参数值
    		return Objects.requireNonNull(expression.getValue(context)).toString();
    	}
    }

案例总结

在上述代码中我有用到 @Aspect@Pointcut@Around 这些概念我先不展开介绍。我们先看看如何使用。具体的概念介绍可以参考 Spring 官网, 或者我之前的文章 Spring Aop 详解

    @DistributedLock(key = "'user_service:user_opt:' + #userModel.name")
    public void save(UserModel userModel) {
        // todo
    }

通过 @DistributedLock 降低了代码的复杂度,而且这样做也利于我们公共组件的封装。

Spring Aop 介入时机

方法入口

Spring Aop 是在 Spring 依赖注入完成之后,初始化 Bean 方法AbstractAutowireCapableBeanFactory.java#initializeBean� 中执行的。我们先来看看具体的代码。

    // bean 初始化方法
    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        invokeAwareMethods(beanName, bean);
    
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化之前
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
    
        try {
            // 执行初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化之后,这里会判断是否需要执行 Aop 代理
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    
        return wrappedBean;
    }

核心处理类

核心处理类是 AbstractAutoProxyCreator 它是实现了 BeanPostProcessor 我们可以先看看它的 postProcessAfterInitialization 方法

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

到了这里我们就可以很容易知道 wrapIfNecessary 就是核心的逻辑处理。

Spring Aop 初始化

我们先来看看 wrapIfNecessary 的具体实现:

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && 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.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        // 判断是否需要进行 Aop
        // Object[] DO_NOT_PROXY = null;
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 创建代理对象
            // new SingletonTargetSource(bean) 被代理对象,就是 Bean
            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;
    }

看到上面的代码我们先梳理一下 这个代理的过程:

  1. 首先获取 advice
  2. 然后判断是否需要代理
  3. 然后执行代理

获取 Advice

获取的入口方法是 getAdvicesAndAdvisorsForBean

    protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    
        // 寻找匹配的 advisor
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

然后通过 findEligibleAdvisors 寻找匹配的 advisor

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 找到所有的 Advisor
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 筛选
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            // 排序
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

findEligibleAdvisors 中会有三个步骤:

  1. 找到所有的 Advisor
  2. 筛选符合条件的 Advisor
  3. 对结果进行排序

我们先来看看 findCandidateAdvisors 是如何查找所有的 Advisor

    protected List<Advisor> findCandidateAdvisors() {
        Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }
    
    // 核心是调用 
    // BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
    public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        // 获取所有的 advisorNames
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the auto-proxy creator apply to them!
            // advisor 的所有 bean 查找
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
        if (advisorNames.length == 0) {
            return new ArrayList<>();
        }
    
    	// 获取所有的 advisors 实例
        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            String bceBeanName = bce.getBeanName();
                            if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                                if (logger.isTraceEnabled()) {
                                    logger.trace("Skipping advisor '" + name +
                                                 "' with dependency on currently created bean: " + ex.getMessage());
                                }
                                // Ignore: indicates a reference back to the bean we're trying to advise.
                                // We want to find advisors other than the currently created bean itself.
                                continue;
                            }
                        }
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }

然后接下来就是对 Advice 进行筛选

    protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    
        ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {
            ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
    }
    
    // 核心是调用 AopUtils.findAdvisorsThatCanApply 方法
    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new ArrayList<>();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }

最后在对这些 Advisor 进行排序

生成代理对象

获取到当前 bean 符合条件的 Advice 过后,Spring 就会进行 Bean 代理对象的创建

    Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

核心就是 createProxy 方法

    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                                 @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    
        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }
    
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);
    
        if (proxyFactory.isProxyTargetClass()) {
            // Explicit handling of JDK proxy targets (for introduction advice scenarios)
            if (Proxy.isProxyClass(beanClass)) {
                // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
                for (Class<?> ifc : beanClass.getInterfaces()) {
                    proxyFactory.addInterface(ifc);
                }
            }
        }
        else {
            // No proxyTargetClass flag enforced, let's apply our default checks...
            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);
    
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
    
        // Use original ClassLoader if bean class not locally loaded in overriding class loader
        ClassLoader classLoader = getProxyClassLoader();
        if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
            classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
        }
        // 获取代理对象
        return proxyFactory.getProxy(classLoader);
    }

选择动态代理

Spring 在进行动态代理的时候会进行选择 GCLIB 或者 JDK 动态代理, 具体在 DefaultAopProxyFactory 中实现的逻辑。 简单的理解为如果 bean 实现了接口就采用 JDK 代理, 如果没有实现就采用 GCLIB 代理,但是会有一些的参数可以特殊控制如: proxyTargetClass,optimize 等 。 代码如下:

    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    
    
        @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (!NativeDetector.inNativeImage() &&
                (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 代理
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                // 否者采用 Cglib 代理
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                // 采用 JDK 代理
                return new JdkDynamicAopProxy(config);
            }
        }
    
        /**
    	 * Determine whether the supplied {@link AdvisedSupport} has only the
    	 * {@link org.springframework.aop.SpringProxy} interface specified
    	 * (or no proxy interfaces specified at all).
    	 */
        private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
            Class<?>[] ifcs = config.getProxiedInterfaces();
            return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
        }
    
    }

最后通过动态的方式完成代理对象的创建。

参考文档