1.概述
上文实现的IOC和AOP功能很单一,且IOC和AOP两个模块没有整合到一起。IOC在加载bean过程中,AOP不能对bean织入通知。升级版IOC和AOP的功能:
1.根据xml配置文件加载相关bean
2.对BeanPostProcessor类型的bean提供支持
3.对BeanFactoryAware类型的bean提供支持
4.实现了基于JDK动态代理的AOP
5.整合了IOC和AOP,使得二者可很好的协同工作
2.IOC的实现
2.1.BeanFactory的生命流程
1.BeanFactory加载Bean配置文件,将读到的Bean配置封装成BeanDefinition对象
2.将封装好的BeanDefinition对象注册到BeanDefinition容器中
3.注册BeanPostProcessor相关实现类到BeanPostProcessor容器中
4.BeanFactory进入就绪状态
5.外部调用BeanFactory的getBean(String name)方法,BeanFactory着手实例化相应的bean
6.重复步骤3和4,直到程序退出,BeanFactory被销毁。
2.2.BeanDefinition及其他一些类的介绍
实现IOC会用到一些辅助类,包括BeanDefinition、BeanReferece、PropertyValues、PropertyValue,这些类与xml的解析紧密相关。先从BeanDefinition开始介绍。
BeanDefinition,从字面意思上翻译成中文就是"Bean的定义",即根据Bean配置信息生成的Bean详情对象。
在具体实现中,BeanDefinition和xml是怎么对应的呢?如图。
上图中的ref对应的BeanReference对象。BeanReference对象保存的是bean配置中ref属性对应的值,在后续BeanFactory实例化bean时,会根据BeanReference保存的值去实例化bean依赖的其他bean。
接下来看看PropertyValue和PropertyValues这两个类。首先是PropertyValue,PropertyValue中有两个字段name和value,用于记录bean配置中的标签的属性值。然后是PropertyValues,PropertyValues从字面意思上来看,是PropertyValue复数形式,在功能上等同于List。那么为什么不直接使用List,而自己定义一个新类呢?答案是要获得一定的控制权,看下面的代码:
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue pv) {
// 这里使用一个PropertyValues来封装,而没有简单使用list的原因是:可以对添加的pv元素,进行操作
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValueList() {
return propertyValueList;
}
}
2.3.xml的解析
BeanFactory初始化时,会根据传入的xml配置文件路径加载并解析配置文件。但是BeanFactory并不处理其他的工作,只管理容器中的bean。于是BeanFactory将加载和解析配置文件的任务委托给BeanDefinitionReader的实现类XmlBeanDefinitionReader去做。那么XmlBeanDefinitionReader具体是怎么做的呢?XmlBeanDefinitionReader做了如下几件事情:
1.将xml配置文件加载到内存中
2.获取根标签下所有的标签
3.遍历获取到的标签列表,并从标签中读取id,class属性
4.创建BeanDefinition对象,并将刚刚读取到的id,class属性值保存到对象中
5.遍历标签下的标签,从中读取属性值,并保持在BeanDefinition对象中
6.将< id, BeanDefintion>键值对缓存在Map中,留作后用
7.重复3、4、5、6步,直到解析结束
2.4.注册BeanPostProcessor
BeanPostProcessor接口是Spring对外扩展的接口之一,其主要用途提供一个机会,让开发人员能够插手bean的实例化过程。通过实现这个接口,我们就可在bean实例化时,对bean进行一些处理。比如,我们所熟悉的AOP就是在这里将切面逻辑织入相关bean中的。正是因为有了BeanPostProcessor接口作为桥梁,才使得AOP可以和IOC容器产生联系。
接下来说说BeanFactory是怎么注册BeanPostProcessor相关实现类的。
XmlBeanDefinitionReader在完成解析工作后,BeanFactory会将它解析得到的< id, BeanDefinition>键值对注册到自己的beanDefinitionMap中。BeanFactory注册好BeanDefinition后,就立即开始注册BeanPostProcessor相关实现类。过程如下:
1.根据BeanDefinition记录的信息,寻找所有实现了BeanPostProcessor接口的类。
2.实例化BeanPostProcessor接口的实现类
3.把实例化好的对象放入List中
4.重复2、3步,直至所有的实现类完成注册
2.5.getBean过程解析
在完成了xml的解析、BeanDefinition的注册以及BeanPostProcessor的注册过程后。BeanFactory初始化的工作就结束了,此时BeanFactory处于就绪状态,等待外部程序的调用。
外部程序一般都是通过调用BeanFactory的getBean(String name)方法来获取容器中的bean。BeanFactory具有延迟实例化bean的特性,也就是等外部程序需要的时候,才实例化相关的bean。这样做的好处是比较显而易见的,第一是提高了BeanFactory的初始化速度,第二是节省了内存资源。Bean的实例化过程:
上图是完整的Spring bean实例化过程图。而这个项目中简化的bean实例化的过程,如下:
简化后的实例化流程如下:
1.实例化bean对象,类似于new XXObject()
2.将配置文件中配置的属性填充到刚刚创建的bean对象中
3.检查bean对象是否实现了Aware一类的接口,如果实现了则把相应的依赖设置到bean对象中。目前仅对BeanFactoryAware接口实现类提供了支持
4.调用BeanPostProcessor前置处理方法,即postProcessBeforeInitialization(Object bean,String name)
5.调用BeanPostProcessor后置处理方法,即postProcessAfterInitializationn(Object bean,String name)
6.bean对象处于就绪状态,可以是用了
源码可以在gitee上下载阅读handwritten_spring。
3.实现AOP
3.1.AOP原理
AOP是基于动态代理模式实现的,具体实现上可以基于JDK动态代理或者Cglib动态代理。其中JDK动态代理只能代理实现了接口的对象,而Cglib动态代理则无此限制。所以在为没有实现接口的对象生成代理时,只能使用cglib。在 handwritten_spring项目中,暂时只实现了基于JDK动态dialing对象生成器。
AOP的流程
1.AOP逻辑介入BeanFactory实例化bean的过程
2.根据Pointcut定义的匹配规则,判断当前正在实例化的bean是否符合规则
3.如果符合代理生成器将切面逻辑Advice织入bean相关方法中,并为目标bean生成代理对象
4.将生成的bean的代理对象返回给BeanFactory容器。到此,AOP逻辑执行结束。
3.2.基于JDK动态代理的AOP实现
在这个项目中,代理对象生成器的逻辑主要写在了JdkDynamicAopProxy类中,这个类的有两个方法,其中getProxy方法用于生成代理对象。invoke方法是InvocationHandler接口的具体实现,包含了将通知(Advice)织入相关方法中,看一下JdkDynamicAopProxy:
JDKDynamicAopProxy实现代码:
public abstract class AbstractAopProxy implements AopProxy{
protected AdvisedSupport advised;
public AbstractAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
}
public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {
public JdkDynamicAopProxy(AdvisedSupport advised) {
super(advised);
}
/**
* 为目标 bean 生成代理对象
* @return bean 的代理对象
* @author ZhouXuan
* @date 2021/12/7 20:40
*/
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this);
}
/**
* InvocationHandler 接口中的 invoke 方法具体实现,封装了具体的代理逻辑
* @param proxy:
* @param method:
* @param args:
* @return java.lang.Object 代理方法或原方法的返回值
* @author ZhouXuan
* @date 2021/12/7 20:48
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodMatcher methodMatcher = advised.getMethodMatcher();
// 使用方法匹配器 methodMatcher 测试 bean 中原始方法 method 是否符合匹配规则
if (methodMatcher != null && methodMatcher.matchers(method, advised.getTargetSource().getTargetClass())) {
// 获取 Advice.MethodInterceptor 的父接口继承了 Advice
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
// 将 bean 的原始 method 封装成 MethodInvocation 实现类对象
// 将生成的对象传给 Advice 实现类对象,执行通知逻辑
return methodInterceptor.invoke(
new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)
);
} else {
// 当前 method 不符合匹配规则,直接调用 bean 中的原始 method
return method.invoke(advised.getTargetSource().getTarget(),args);
}
}
}
下面这个流程图对织入逻辑进行总结:
对JdkDynamicAopProxy进行简单的测试,测试代码及结果如下
测试类:
public class LogInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod().getName() + " method start");
Object obj = invocation.proceed();
System.out.println(invocation.getMethod().getName() + " method end");
return obj;
}
}
public class JdkDynamicAopProxyTest {
@Test
public void getProxy() throws Exception {
System.out.println("-----no proxy-----");
HelloService helloService = new HelloServiceImpl();
helloService.sayHelloWorld();
System.out.println("--------proxy------");
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setMethodInterceptor(new LogInterceptor());
TargetSource targetSource = new TargetSource(helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces());
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true);
helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy();
helloService.sayHelloWorld();
}
}
测试结果:
3.3.AOP与IOC协作
在 handwritten_spring中,AOP和IOC产生联系的具体实现类是AspectJAwareAdvisorAutoProxyCreator(下面简称AutoProxyCreator),这个类实现了BeanPostProcessor和BeanFactoryAware接口。BeanFactory在注册BeanPostProcessor接口相关实现类的阶段,会将其本身注入到AutoProxyCreator中,为后面AOP给bean生成代理对象做准备。BeanFactory初始化结束后,AOP与IOC桥梁类AutoProxyCreator也完成了实例化,并被缓存在BeanFactory中,静待BeanFactory实例化bean。当外部产生调用,BeanFactory开始实例化bean时。AutoProxyCreator也开始工作了,工作细节如下:
1.从BeanFactory查找实现了PointcutAdvisor接口的切面对象,切面对象中包含了实现Pointcut和Advice接口的对象。
2.使用Pointcut中的表达式对象匹配当前bean对象。如果匹配成功,进行下一步。否则终止逻辑,返回bean。
3.JdkDynamicAopProxy对象为匹配到的bean生成代理对象,并将代理对象返回给BeanFactory。
经过上面3步,AutoProxyCreator就把原来的bean替换为代理对象了。最后handwritten_spring AOP剩余的实现代码贴出来:
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {
private XmlBeanFactory xmlBeanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// 这里两个if判断很有必要,如果删除将会使程序进入死循环状态
// 最终导致 StackOverflowError 错误发生
if (bean instanceof AspectJExpressionPointcutAdvisor) {
return bean;
}
if (bean instanceof MethodInterceptor) {
return bean;
}
// 1. 从BeanFactory 查找 AspectJExpressionPointcutAdvisor 类型的对象
List<AspectJExpressionPointcutAdvisor> advisors = xmlBeanFactory.getBeansForType(AspectJExpressionPointcut.class);
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
// 2.使用 Pointcut 对象匹配当前 bean对象
if (advisor.getPointcut().getClassFilter().matchers(bean.getClass())) {
ProxyFactory advisedSupport = new ProxyFactory();
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
// 3.生成代理对象,并返回
return advisedSupport.getProxy();
}
}
// 3.匹配失败,返回 bean
return bean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws Exception {
xmlBeanFactory = (XmlBeanFactory) beanFactory;
}
}
ProxyFactory实现代码:
public class ProxyFactory extends AdvisedSupport implements AopProxy{
@Override
public Object getProxy() {
return createAopProxy().getProxy();
}
private AopProxy createAopProxy() {
return new JdkDynamicAopProxy(this);
}
}
测试类:
public class XmlBeanFactoryTest {
@Test
public void getBean() throws Exception {
System.out.println("------AOP test---------");
String location = getClass().getClassLoader().getResource("toy-spring.xml").getFile();
XmlBeanFactory bf = new XmlBeanFactory(location);
HelloService helloService = (HelloService)bf.getBean("helloService");
helloService.sayHelloWorld();
}
}
测试结果:
·