【04】Spring源码-手写篇-手写AOP实现(下)

2022-09-28 13:03:55 浏览数 (1)

接上一篇文章继续

四、织入实现

1. 织入的分析

  织入要完成的是什么?织入其实就是要把用户提供的增强功能加到指定的方法上。

思考1:在什么时候织入?

  创建Bean实例的时候,在Bean初始化后,再对其进行增强。

思考2:如何确定bean要增强?

  对bean类及方法挨个匹配用户配置的切面,如果有切面匹配就是要增强

思考3:如何实现织入?

  代理方式

2.织入的设计

  为了更好的去设计织入的实现,先整理下AOP的使用流程。

这里我们要考虑匹配、织入逻辑写到哪里?是写在BeanFactory中吗?

这时我们要考虑如果我们直接在BeanFactory中来处理,后续如果还有其他的需求是不是也要在BeanFactory中处理呢?这样操作有什么不好的地方呢?

  • BeanFactory代码爆炸,不专情
  • 不易扩展

那我们应该要怎么来设计呢?

我们先来回顾下Bean的生产的过程

在这个过程中, 将来会有更多处理逻辑加入到Bean生产过程的不同阶段。我们现在最好是设计出能让我们后面不用再改BeanFactory的代码就能灵活的扩展。

这时我们可以考虑用观察者模式,通过在各个节点加入扩展点,加入注册机制。

那么在这块我们就应用观察者模式来加入一个Bean的后置处理器 BeanPostProcessor

具体的我们在代码中来看看。

3.织入的实现

3.1 分析

  我们先定义了 BeanPostProcessor 接口,在这个接口中我们定义了相关的行为,也就是初始化之前和初始化之后要执行的方法。

  那么在此处我们需要在BeanFactory对创建的Bean对象做初始化前后要校验是否需要做相关的增强操作。

  在BeanFactory中我们提供了BeanPostProcessor的注册方法。

那么结合BeanFactory要实现相关的Bean增强操作,我们要做的行为就是两方面

  1. 创建相关的BeanPostProcessor,并注册到BeanFactory中
  2. BeanFactory在初始化Bean前后判断是否有相关BeanPostProcessor,如果有做相关的增强处理

  有了上面的分析,那么我们要实现具体的织入就需要来看看在对应前置和后置方法中我们要实现的功能

3.2 判断是否需要增强

  我们如何判断Bean对象是否需要增强呢?其实就是需要判断该Bean是否满足用户定义的切入点表达式。也就是我们需要简单Bean所属的类和所有方法。然后遍历Advisor。取出advisor中的Pointcut来匹配类和方法。

代码层面

代码语言:javascript复制
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Throwable {

		/*逻辑
		1 判断Bean是否需要增强
		2 创建代理来实现增强
		*/

        //1 判断Bean是否需要增强
        List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);

		// 2如有切面切中,创建代理来实现增强
		if (CollectionUtils.isNotEmpty(matchAdvisors)) {
			bean = this.createProxy(bean, beanName, matchAdvisors);
		}

        return bean;
    }

3.3 代理对象

  通过上面的分析如果Bean需要被增强,那么我们就需要创建Bean对应的代理对象了。代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在调用者和目标对象之间起到中介的作用;

  动态代理的实现方法有哪些?

JDK动态代理:

在运行时,对接口创建代理对象

cglib动态代理:

3.4 代理实现层设计

  动态代理的实现方式有很多种,如何能够做到灵活的扩展呢?在这里我们同样可以通过 抽象面向接口编程来设计一套支持不同代理实现的代码

  有了上面的设计,然后就是需要考虑代理对象的创建了。

3.5 增强逻辑实现

  代理对象搞定后我们需要考虑核心的问题就是怎么来实现我们要增强的逻辑呢?首先不管你用哪种方式来生成代理对象最终增强的逻辑代码是一样的。所以我们可以把这部分内容提炼出来。

  然后具体的应用Advice增强实现的逻辑为:

注意此处用到了责任链模式

代码语言:javascript复制
	public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> matchAdvisors,
			Object proxy, BeanFactory beanFactory) throws Throwable {
		// 这里要做什么?   需要获取相关案例代码的 V:boge3306 备注:手写Spring
		// 1、获取要对当前方法进行增强的advice
		List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, matchAdvisors,
				beanFactory);
		// 2、如有增强的advice,责任链式增强执行
		if (CollectionUtils.isEmpty(advices)) {
			return method.invoke(target, args);
		} else {
			// 责任链式执行增强
			AopAdviceChainInvocation chain = new AopAdviceChainInvocation(proxy, target, method, args, advices);
			return chain.invoke();
		}
	}

然后我们前面的Creator要怎么使用AopProxy呢?这块我们可以通过工厂模式来处理

代码语言:javascript复制
public interface AopProxyFactory {

	AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
			throws Throwable;

	/**
	 * 获得默认的AopProxyFactory实例
	 *    需要获取相关案例代码的 V:boge3306 备注:手写Spring
	 * @return AopProxyFactory
	 */
	static AopProxyFactory getDefaultAopProxyFactory() {
		return new DefaultAopProxyFactory();
	}
}

到这儿,完整的增强逻辑就梳理通了

0 人点赞