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

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

本次我们一起来聊一下 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])));
    }

}
复制代码

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

参考文档

猜你喜欢

转载自juejin.im/post/7017463197514858526