0
点赞
收藏
分享

微信扫一扫

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


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

接上一篇文章继续

四、织入实现

1. 织入的分析

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

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

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

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

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

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

思考3:如何实现织入?

  代理方式

2.织入的设计

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_03

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

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

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

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

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

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

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

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

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

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_06

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

3.织入的实现

3.1 分析

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

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

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_08

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_09

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_10

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

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

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

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

3.2 判断是否需要增强

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

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

代码层面

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

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

3.3 代理对象

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

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

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

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

JDK动态代理:

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

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

cglib动态代理:

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_17

3.4 代理实现层设计

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_18

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

【04】Spring源码-手写篇-手写AOP实现(下)_初始化_19

3.5 增强逻辑实现

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

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

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

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

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

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呢?这块我们可以通过工厂模式来处理

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

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 条评论