[手写spring](4)实现后置处理器
  TEZNKK3IfmPf 2023年11月12日 21 0

目标

        后置处理器算是实现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 {
}

         项目结构如下

[手写spring](4)实现后置处理器

        在测试类中只需创建一个容器即可,如下

public class MySpringTest {

    public static void main(String[] args) {
        ApplicationContext ioc = new ApplicationContext(ComponentScanPathConfig.class);
    }
}

         控制台输出如下

[手写spring](4)实现后置处理器

         经过测试,可以发现,我们的后置处理器也没有问题。


总结

        经过这篇文章,我们已经实现了后置处理器,难度总体来说还不算特别大,在下一篇文章中我们将会实现spring的核心机制--AOP,这也是比较难的一点,我自己写的时候也调了很久的bug,做好准备,开始实现AOP吧!!!


 手写spring系列 

[手写spring](1)构建框架,实现包扫描

[手写spring](2)初始化BeanDefinitionMap

[手写spring](3)初始化singletonObjects,实现依赖注入

[手写spring](4)实现后置处理器

[手写spring](5)实现AOP机制(完结)  

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   20天前   46   0   0 java
TEZNKK3IfmPf