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

导读:本篇文章讲解 [手写spring](4)实现后置处理器,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

目标

自定义注解

自定义接口

执行bean的初始化方法

创建后置处理器名称Set

初始化后置处理器名称集合

执行后置处理器方法

执行所有postProcessBeforeInitialization方法

执行所有postProcessAfterInitialization方法

调用初始化方法、后置处理器方法

测试

总结


目标

        后置处理器算是实现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机制(完结)  

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/74825.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!