目标
后置处理器算是实现AOP的前提,我们在这篇文章中就将会实现后置处理器,后置处理器是什么我就不介绍了,不清楚可以参考后置处理器,下面直接开始。
自定义注解
我们定义一个注解来标识bean的初始化方法。
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface PostConstruct {
}
自定义接口
我们定义一个后置处理器的接口,里面的2个方法和原生的spring是一样的。如果一个类实现了这个接口,那么这个类就是后置处理器类。
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return bean;
}
}
执行bean的初始化方法
我们创建一个方法,这个方法判断一个类是否有需要进行执行的初始化方法,也就是判断方法上有没有@PostConstruct注解
protected void executeInitMethod(Object o) {
for (Method method : o.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
try {
method.invoke(o);
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
创建后置处理器名称Set
我们创建一个set来将后置处理器的名称存放到里面,方便后续处理
private Set<String> beanPostProcessorNames;
//代码块初始化集合
{
beanPostProcessorNames = new HashSet<>();
}
初始化后置处理器名称集合
我们在初始化singletonObjects集合的时候,需要对beanDefinitionMap进行遍历,我们可以在遍历的时候初始化后置处理器名称的集合,只需要判断是否实现BeanPostProcessor接口即可
//将后置处理器的名字存储进set中
if (bean instanceof BeanPostProcessor) {
beanPostProcessorNames.add(name);
}
执行后置处理器方法
我们需要遍历后置处理器,并且执行所有的before和after方法,所以我们可以提供2个方法,分别完成执行before和after的功能
执行所有postProcessBeforeInitialization方法
protected Object processorBeforeMethod(Object o, String beanName) {
for (String postProcessorName : beanPostProcessorNames) {
BeanPostProcessor postProcessor = (BeanPostProcessor) singletonObjects.get(postProcessorName);
Object current = null;
try {
current = postProcessor.postProcessBeforeInitialization(o, beanName);
} catch (Exception e) {
e.printStackTrace();
}
if (current != null) {
o = current;
}
}
}
执行所有postProcessAfterInitialization方法
protected Object processorAfterMethod(Object o, String beanName) {
for (String postProcessorName : beanPostProcessorNames) {
BeanPostProcessor postProcessor = (BeanPostProcessor) singletonObjects.get(postProcessorName);
Object current = null;
try {
current = postProcessor.postProcessAfterInitialization(o, beanName);
} catch (Exception e) {
e.printStackTrace();
}
if (current != null) {
o = current;
}
}
return o;
}
调用初始化方法、后置处理器方法
在上面,我们实现了初始化方法,后置处理器方法,现在我们在对象创建后进行显示调用,相当于要在2个地方进行调用,分别是解决singletonObjects依赖注入之后,如下
//如果是自身就是后置处理器,跳过
if (o instanceof BeanPostProcessor) continue;
//后置处理器
o = processorBeforeMethod(o, beanName);
//调用init方法
executeInitMethod(o);
//后置处理器
o = processorAfterMethod(o, beanName);
//更新单例对象池中的对象
singletonObjects.put(beanName, o);
然后还需要在createBean方法中进行调用。在返回之前调用即可
//后置处理器
o = processorBeforeMethod(o, beanName);
//调用init方法
executeInitMethod(o);
//后置处理器
o = processorAfterMethod(o, beanName);
测试
为了方便,我们在test包下面新建2个子包,分别是bean包和processor包,bean包里面写随便写一个类,提供一个init方法。processor包下写一个类继承BeanPostProcessor接口。
@Component
public class Cat {
@PostConstruct
public void myInit(){
System.out.println("这是Cat的初始化方法");
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
System.out.println(beanName+"的后置处理器--before");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
System.out.println(beanName+"的后置处理器--after");
return bean;
}
}
更改我们spring的扫描路径,也就是在更改ComponentScan注解
@ComponentScan(path = "com.ttpfx.use.test")
public class ComponentScanPathConfig {
}
项目结构如下
在测试类中只需创建一个容器即可,如下
public class MySpringTest {
public static void main(String[] args) {
ApplicationContext ioc = new ApplicationContext(ComponentScanPathConfig.class);
}
}
控制台输出如下
经过测试,可以发现,我们的后置处理器也没有问题。
总结
经过这篇文章,我们已经实现了后置处理器,难度总体来说还不算特别大,在下一篇文章中我们将会实现spring的核心机制--AOP,这也是比较难的一点,我自己写的时候也调了很久的bug,做好准备,开始实现AOP吧!!!
手写spring系列
[手写spring](1)构建框架,实现包扫描
[手写spring](2)初始化BeanDefinitionMap
[手写spring](3)初始化singletonObjects,实现依赖注入
[手写spring](4)实现后置处理器
[手写spring](5)实现AOP机制(完结)