在上一篇中已经讲到了Advisor包下的Advisor.java,也就是一个通知者和一个基于AspectJ语法实现的Advisor,因为通知者也可分为许多不一样种类的通知者,因此咱们在进行扩展的时候,须要经过不一样的实现方式定义不一样的通知者。java
如今看看这两种不一样的设计方式spring
第二种相比第一种多了一层抽象,把相同的属性方法抽离掉而后减小了冗余代码, 此时pointcut的生成必须由抽象类AbstractPointcutAdvisor的子类去实现生成不一样的 pointcut,是AspectJ的生成AspectJ的,是正则Reg的生成正则的。编程
将用户提供的加强功能加到指定的方法上
复制代码
建立bean实例,在bean初始化后进行加强
复制代码
对bean类及方法进行遍历,匹配用户指定的切面
复制代码
代理!
复制代码
此时咱们回顾一下AOP的使用流程api
用户---> 配置并注册切面
咱们---> 织入流程:初始化bean---判断是否须要加强 ? 代理加强---返回实例 : 返回实例
复制代码
还记得咱们以前实现的DefaultBeanFactory吗?
在它的doGetBean方法中,初始化Bean前增长一个加强逻辑便可
复制代码
后续咱们在bean建立过程当中还会再加入更多不一样的处理,若是直接在BeanFactory中实现,会致使BeanFactory代码爆炸性增加,并且也不容易进行扩展,此时咱们该如何处理呢?缓存
此时咱们再回顾一下3周前的那篇《手写Spring---IOC容器(1)》中讲到的Bean的产出过程app
1.建立Bean定义---① 2.注册Bean定义②---③ 3.建立Bean实例④---⑤ 4.初始化Bean实例⑥
在此4个节点中,每一项过程的先后阶段均可能增长各类各样的处理逻辑
为了让咱们更加灵活,设计好BeanFactory后不须要修改代码,
咱们须要在各个节点中加入扩展点(使用了 **① ~ ⑥** 标识,
好比**①**的意思为注册bean定义前,**②**为注册Bean定义后)和注册机制
复制代码
此时咱们须要会想到观察者模式(监听模式),须要六个扩展点,也就是六个观察者maven
此时咱们不推荐仅定义一个接口去完成全部扩展点的监听,由于它们的用途不同且实现的时候须要一会儿实现6个功能,此时咱们定义一个监听接口BeanPostProcessor来监听Bean初始化先后过程,具体流程参照下图:ide
这里默认什么都不干,定义的是default默认方法,这里是为了方便选择只进行某一个的扩展点的处理,好比咱们以后就只选择进行初始化后的处理工具
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean,String beanName) throws Throwable{
return bean;
}
default Object postProcessAfterInitialization(Object bean,String beanName) throws Throwable{
return bean;
}
}
复制代码
提供对于Advisor的注册和获取post
public interface AdvisorRegistry {
public void registAdvisor(Advisor ad);
public List<Advisor> getAdvisors();
}
复制代码
此时咱们建立好实例以后须要放入Bean工厂里面,还须要在BeanFactory.java中加入注册监听的方法
public interface BeanFactory {
Object getBean(String name) throws Throwable;
//新加入的注册方法
void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}
复制代码
这里是BeanFactory的默认实现,在此提供registerBeanPostProcessor的实现
(1)定义一个集合
private List<BeanPostProcessor> beanPostProcessors = Collections.synchronizedList(new ArrayList<>());
复制代码
(2)注册方法(仅仅为添加进线程同步集合beanPostProcessors中)
@Override
public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof BeanFactoryAware){
((BeanFactoryAware) beanPostProcessor).setBeanFactory(this);
}
}
复制代码
如何去使用观察者模式,还必须提供唤醒的功能
(1)此时在Bean初始化前和初始化后加入处理(DefaultBeanFactory中的doGetBean方法)
// 应用bean初始化前的处理
instance = this.applyPostProcessBeforeInitialization(instance, beanName);
// 执行初始化方法
this.doInit(bd, instance);
// 应用bean初始化后的处理
instance = this.applyPostProcessAfterInitialization(instance, beanName);
复制代码
(2)applyPostProcessBeforeInitialization()和applyPostProcessAfterInitialization()方法其实就是遍历你的全部注册进来的processor,而后一个一个调用它们的方法,按照这个规范来扩展多少功能均可以
// 应用bean初始化前的处理
private Object applyPostProcessBeforeInitialization(Object bean, String beanName) throws Throwable {
for (BeanPostProcessor bpp : this.beanPostProcessors) {
bean = bpp.postProcessBeforeInitialization(bean, beanName);
}
return bean;
}
// 应用bean初始化后的处理
private Object applyPostProcessAfterInitialization(Object bean, String beanName) throws Throwable {
for (BeanPostProcessor bpp : this.beanPostProcessors) {
bean = bpp.postProcessAfterInitialization(bean, beanName);
}
return bean;
}
复制代码
AOP 织入功能 applyPostProcessAfterInitialization 确定在此实现
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Throwable {
}
复制代码
回忆这个过程: 织入流程:初始化bean---判断是否须要加强 ? 代理加强---返回实例 : 返回实例
1.获取bean的类及全部方法(经过反射getMethods()和getDeclareMethods())
2.遍历Advisor,取advisor中的Pointcut来匹配类和方法
Pointcut中的两个匹配方法:
boolean matchClass(Class<?> targetClass);
boolean matchMethod(Method method,Class<?> targetClass);
便是用前面经过反射得到的方法和matchMethod()来比较
复制代码
若是阅读过源码中的说明,就会发现getMethods()方法返回全部的公开方法,
没法取得私有和保护类型的方法,getDeclareMethods()没法取得父类
的继承方法(第一小段最后一句but excluding inherited methods)
因此这两个方法仍然不够,咱们到时候会直接使用spring里面内置的方法
复制代码
// 第一步:在此判断bean是否须要进行切面加强
List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);
// 第二步:如须要就进行加强,建立代理对象,进行代理加强。再返回加强的对象。
if (CollectionUtils.isNotEmpty(matchAdvisors)) {
bean = this.createProxy(bean, beanName, matchAdvisors);
}
复制代码
private List<Advisor> getMatchedAdvisors(Object bean, String beanName) {
if (CollectionUtils.isEmpty(advisors)) {
return null;
}
// 获得类、全部的方法
Class<?> beanClass = bean.getClass();
List<Method> allMethods = this.getAllMethodForClass(beanClass);
// 存放匹配的Advisor的list
List<Advisor> matchAdvisors = new ArrayList<>();
// 遍历Advisor来找匹配的
for (Advisor ad : this.advisors) {
if (ad instanceof PointcutAdvisor) {
if (isPointcutMatchBean((PointcutAdvisor) ad, beanClass, allMethods)) {
matchAdvisors.add(ad);
}
}
}
return matchAdvisors;
}
复制代码
此时咱们须要用到Spring自带的ClassUtils和ReflectionUtils,ps:能够直接在maven中添加SpringBoot的依赖以后无须再进行导包。
这里的逻辑为建立一个集合,使用ClassUtils自带的遍历方法getAllInterfacesForClassAsSet()遍历全部接口,以后把自身beanClass也一块儿丢进这个集合中,以后来一个循环把接口中的全部方法依次遍历出来
private List<Method> getAllMethodForClass(Class<?> beanClass) {
List<Method> allMethods = new LinkedList<>();
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
classes.add(beanClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method m : methods) {
allMethods.add(m);
}
}
return allMethods;
}
复制代码
private boolean isPointcutMatchBean(PointcutAdvisor pa, Class<?> beanClass, List<Method> methods) {
Pointcut p = pa.getPointcut();
// 首先判断类是否匹配
// 注意以前说过的AspectJ状况下这个匹配是不可靠的,须要经过方法来匹配
//这里的判断仅仅起到过滤做用,类不匹配的前提下直接跳过
if (!p.matchClass(beanClass)) {
return false;
}
// 再判断是否有方法匹配
for (Method method : methods) {
if (p.matchMethod(method, beanClass)) {
return true;
}
}
return false;
}
复制代码
此时咱们已经获得了匹配上的方法,能够对这些方法进行代理加强操做了
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Throwable {
// 在此判断bean是否须要进行切面加强
List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);
// 如须要就进行加强,再返回加强的对象。
if (CollectionUtils.isNotEmpty(matchAdvisors)) {
bean = this.createProxy(bean, beanName, matchAdvisors);
}
return bean;
}
复制代码
private Object createProxy(Object bean, String beanName, List<Advisor> matchAdvisors) throws Throwable {
// 经过AopProxyFactory工厂去完成选择、和建立代理对象的工做。
return AopProxyFactory.getDefaultAopProxyFactory().createAopProxy(bean, beanName, matchAdvisors, beanFactory)
.getProxy();
}
复制代码
这部分涉及的内容比较多,建议先理清思路而后看懂逻辑便可,由于咱们的主要出发点在于之后可以理解源码而不是真的要本身完整实现一个spring
代理可分为jdk动态代理(使用invoke方法加强)和cglib动态代理(使用intercept方法加强),判断代理生成方式后返回相应代理对象便可
复制代码
咱们知道,要实现jdk动态代理,就要实现InvocationHandler接口,要实现cglib动态代理,就要实现MethodInteceptor接口,咱们能够对这二者进行抽象,抽成一个AopProxy接口,里面提供获取代理对象的方法便可
public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}
复制代码
同样,都是使用Advice进行加强
---> 从Advisor中找出对当前方法进行加强的Advice
---> 是否有匹配的Advice?责任链式应用Advice加强:执行被代理对象的方法
---> 返回结果
jdk要生成代理对象,完成织入加强,须要如下数据
要实现的接口,目标对象,匹配的Advisors,可能还须要BeanFactory
cglib须要的数据:
要继承的类,实现的接口,构造参数类型,构造参数,目标对象,
匹配的Advisor和BeanFactory
为什么须要构造参数和构造参数类型,由于扩展目标类若是没提供无参构造方法,那它的子类建立时必须调用父类的有参构造方法
复制代码
先不看JdkDynamicAopProxy和CglibDynamicAopProxy的具体实现,咱们先看它们的结构,由于前面咱们也提到了,它们俩作的事情,功能实际上是同样的,因此能够提取相同的功能实现部分为一个通用方法applyAdvices()
咱们能够直接定义一个工具类AopProxyUtils来储存这样的通用方法
public static Object applyAdvices(Object target, Method method, Object[] args,
List<Advisor> matchAdvisors,Object proxy, BeanFactory beanFactory) throws Throwable {
// 这里要作什么?
// 一、获取要对当前方法进行加强的advice
List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, matchAdvisors,
beanFactory);
// 二、若有加强的advice,责任链式加强执行
if (CollectionUtils.isEmpty(advices)) {
return method.invoke(target, args);
} else {
// 责任链式执行加强
AopAdviceChainInvocation chain = new AopAdviceChainInvocation(proxy, target, method, args, advices);
return chain.invoke();
}
}
public static List<Object> getShouldApplyAdvices(Class<?> beanClass, Method method, List<Advisor> matchAdvisors,
BeanFactory beanFactory) throws Throwable {
if (CollectionUtils.isEmpty(matchAdvisors)) {
return null;
}
List<Object> advices = new ArrayList<>();
for (Advisor ad : matchAdvisors) {
if (ad instanceof PointcutAdvisor) {
if (((PointcutAdvisor) ad).getPointcut().matchMethod(method, beanClass)) {
advices.add(beanFactory.getBean(ad.getAdviceBeanName()));
}
}
}
return advices;
}
复制代码
如何来进行责任链的加强,注意咱们必须定义一个责任链记录索引,好比下方代码中咱们就使用i做为索引,在invoke()方法中,先判断i是否小于advices的size,若是小于,那就是还有加强未执行,以后的判断逻辑很简单,若是这个加强是前置加强,那就是直接执行便可,
若是是环绕加强return ((MethodSurroudAdvice) advice).invoke(invokeMethod, null, this),参考MethodSurroudAdvice中的invoke()的参数,此时咱们须要理解,这里的invoke方法中的invokeMethod对象取得的就是public Object invoke() throws Throwable这个方法自己,null表示无参数,this表示自身
后置加强是返回结果后加强,因此先去调用invoke---Object returnValue = this.invoke();,而后再加强
若是i<advices.size()不成立,那就执行目标方法return method.invoke(target, args);
public class AopAdviceChainInvocation {
private static Method invokeMethod;
static {
try {
invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
private Object proxy;
private Object target;
private Method method;
private Object[] args;
private List<Object> advices;
public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
super();
this.proxy = proxy;
this.target = target;
this.method = method;
this.args = args;
this.advices = advices;
}
// 责任链执行记录索引号
private int i = 0;
public Object invoke() throws Throwable {
if (i < this.advices.size()) {
Object advice = this.advices.get(i++);
if (advice instanceof MethodBeforeAdvice) {
// 执行前置加强
((MethodBeforeAdvice) advice).before(method, args, target);
} else if (advice instanceof MethodSurroudAdvice) {
// 执行环绕加强和异常处理加强。注意这里给入的method 和 对象 是invoke方法和链对象
return ((MethodSurroudAdvice) advice).invoke(invokeMethod, null, this);
} else if (advice instanceof AfterReturningAdvice) {
// 当是后置加强时,先得获得结果,再执行后置加强逻辑
Object returnValue = this.invoke();
((AfterReturningAdvice) advice).afterReturning(returnValue, method, args, target);
return returnValue;
}
return this.invoke();
} else {
return method.invoke(target, args);
}
}
}
复制代码
jdk:
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
private String beanName;
private Object target;
private List<Advisor> matchAdvisors;
private BeanFactory beanFactory;
public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
super();
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("为" + target + "建立代理。");
}
return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
}
}
复制代码
cglib:
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
private static final Log logger = LogFactory.getLog(CglibDynamicAopProxy.class);
private static Enhancer enhancer = new Enhancer();
private String beanName;
private Object target;
private List<Advisor> matchAdvisors;
private BeanFactory beanFactory;
public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
super();
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("为" + target + "建立cglib代理。");
}
Class<?> superClass = this.target.getClass();
enhancer.setSuperclass(superClass);
enhancer.setInterfaces(this.getClass().getInterfaces());
enhancer.setCallback(this);
Constructor<?> constructor = null;
try {
constructor = superClass.getConstructor(new Class<?>[] {});
} catch (NoSuchMethodException | SecurityException e) {
}
if (constructor != null) {
return enhancer.create();
} else {
BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
}
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
}
复制代码
两个动态代理也只是用了它们自己的一些api而已,咱们只须要看懂咱们的逻辑便可,注意的是cglib的动态代理中咱们必须作到传递构造参数类型和构造参数,此时咱们又有了新的问题
如何传递建立bean实例时得到的数据到初始化后的aop中
建立时,是在defaultBeanFactory来进行操做
加强时,通过了AdvisorAutoProxyCreator
使用时,又在CglibDynamicAopProxy
此时咱们考虑将参数放在bean定义中使用ThreadLocal持有参数值,
由于BeanDefinition是同一个类的多个实例。
特别是prototype的时候,是共享的,
咱们须要保证每个建立流程中都是使用不一样线程的数据
复制代码
咱们在BeanDefinition中加入了两个方法:由于咱们自己在BeanDefiniion中就已经有了构造器的缓存(public Constructor getConstructor(); public void setConstructor(Constructor constructor);),参数类型咱们能够经过它们来得到
List<?> getConstructorArgumentValues();
public Object[] getConstructorArgumentRealValues();
复制代码
咱们能够经过CglibDynamicAopProxy中的getProxy方法来更好理解
else {
BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
}
复制代码
这里就是使用了getConstructor()来取得构造器,而后调用 getParameterTypes()来取得了构造参数的类型
应用工厂模式把选择的逻辑交给工厂
public interface AopProxyFactory {
AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
throws Throwable;
/**
* 得到默认的AopProxyFactory实例
*
* @return AopProxyFactory
*/
static AopProxyFactory getDefaultAopProxyFactory() {
return (AopProxyFactory) new DefaultAopProxyFactory();
}
}
复制代码
以后咱们实现了一个默认的工厂,这里作了判断是使用jdk仍是cglib,咱们省略了判断而直接使用了cglib,spring源码里面的判断也是如此,可是源码还另外存在某些机制来判断,在这里咱们也再也不过多阐述了,在之后源码解读的时候会再展开
public class DefaultAopProxyFactory implements AopProxyFactory{
@Override
public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
throws Throwable {
// 是该用jdk动态代理仍是cglib?
if (shouldUseJDKDynamicProxy(bean, beanName)) {
return new JdkDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
} else {
return new CglibDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
}
}
private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
// 如何判断?有实现接口就用JDK,没有就用cglib?
return false;
}
}
复制代码
测试代码相对仍是较多,就不粘贴出来了,AOP这一篇的代码不少,并且比较凌乱(本身都这么以为),须要多花时间去整理总结,有必要的话在以后会再一次进行一次更加详细点的总结篇,把一些过程再讲述清楚点。有问题或者是建议可在留言区提出让我改进。共勉,谢谢。