代码编织梦想

目录

目标

自定义注解

自定义接口

执行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 {
}

         项目结构如下

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

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机制(完结)  

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_51545690/article/details/125544613

spring aop底层原理详解(利用spring后置处理器实现aop)_baomw的博客-爱代码爱编程_spring aop底层实现原理

写在前面:对于一个java程序员来说,相信绝大多数都有这样的面试经历,面试官问:你知道什么是aop吗?谈谈你是怎么理解aop的?等等诸如此类关于aop的问题。当然对于一些小白可能会一脸懵逼;对于一些工作一两年的,可能知道,哦

SpringAOP的应用实例及自定义后置处理器-爱代码爱编程

aspectj依赖的jar包 <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId&g

ssm框架之spring的bean作用域,生命周期,后置处理器,连接池,自动装配-爱代码爱编程

网页左边,向下滑有目录索引,可以根据标题跳转到你想看的内容1、Bean的作用域 上节链接,本节与上节内容相连https://blog.csdn.net/grd_java/article/details/104703294 首先需要了解一下几个概念,这里我重写了Car实体类的无参构造,添加了输出语句System.out.println(“Car类构造器被

纯手写实现Spring源码框架(一)-爱代码爱编程

前端时间学习了一下Spring的源码,整体框架知道个大概,但是不是特别清晰,现在通过自己手写一下回忆一下。 1.准备 1.回忆一下Spring的创建步骤 this() 1.构建BeanFctory工厂,赋值给reader2.构建扫描对象,赋值给scannersan() 1.递归扫描文件路径,奖类解码进BeanDefinitio

手写Mybatis和Spring整合简单版示例窥探Spring的强大扩展能力-v5.3.9-爱代码爱编程

Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework The Spring Framework provides a comprehensive programming and configurati

手写Mybatis整合Spring示例,原来Spring的扩展能力这么强大-爱代码爱编程

Spring之所以能打败其他所有同类型Java开发框架屹立不倒的重要原因之一就是提供很多扩展点,让其他组件和框架很容易就整合到Spring框架里,所以也就诞生很多基于Spring的二次开发项目,接下来我们一起聊聊Spring提供哪些扩展点,这篇文章只是简单说明扩展点但不深入,有兴趣的伙伴可以后续一起学习交流,本篇最后我们再进行一个Mybatis和Sprin

spring高级篇-基于beandefinitionregistrypostprocessor手写后置处理器_dudu0917的博客-爱代码爱编程

上一篇文章中通过ConfigurationClassPostProcessor、MapperScannerConfigurer扫描到了Config类中定义的Bean信息。这篇文章来手动实现这些扫描类的功能。 如何扫描到定义的类加入到容器中? BeanDefinitionRegistryPostProcessor接口继承BeanFactoryPost

springboot 整合 xxljob 动态api调度任务(进阶篇)_小目标青年的博客-爱代码爱编程

前言 之前写了一篇 xxljob的新手入门篇: Springboot 整合 xxljob 使用定时任务调度(新手入门篇)_小目标青年的博客-CSDN博客 这一篇非常非常简单,就是非常快速的springboot整合 xxljob,相当于拿来即用,能够通过页面配合代码去实现定时任务的使用。 这一篇,我们将在上一篇的基础上,做一些进阶使用

17. spring boot整合thymeleaf_bzhyan的博客-爱代码爱编程

Spring Boot 推荐使用 Thymeleaf 作为其模板引擎。SpringBoot 为 Thymeleaf 提供了一系列默认配置,项目中一但导入了 Thymeleaf 的依赖,相对应的自动配置 (ThymeleafAutoConfiguration) 就会自动生效,因此 Thymeleaf 可以与 Spring Boot 完美整合 。 Spring

使用spring boot和jpa创建graphql api_javashark的博客-爱代码爱编程

GraphQL既是API查询语言,也是使用当前数据执行这些查询的运行时。GraphQL让客户能够准确地要求他们所需要的东西,仅此而已,使API随着时间的推移更容易发展,并通过提供API中数据的清晰易懂的描述,支持强大的开发工具。 在本文中,我们将创建一个简单的机场位置应用程序。 生成项目 去 https://start.spring.io/ 

jpa、hibernate、spring-data-jpa关系_程序三两行的博客-爱代码爱编程

1、jpa、hibernate、spring-data-jpa关系 JPA的是 Java Persistence API 的简写,JPA是一套规范,而不是具体的ORM框架。故Hibernate、TopLink 等ORM框架 都是JPA的实现,其中Hibernate已获得Sun的兼容认证。 开发者面向JPA规范的接口,但底层的JPA实现可以任意切换:觉得

【开发心得】记录一次自定义starter的实现_虹梦未来的博客-爱代码爱编程

SpringBoot强大特性之一便是自动配置,约定大于配置。 网上类似的文章很多,比如这篇: SpringBoot之自定义starter_小彭不会秃头的博客-CSDN博客_springboot自定义starter目录一、什么是SpringBoot starter机制二、为什么要自定义starter三、什么时候需要创建自定义starter四、自动加载核心

spring boot技术知识点:如何实现二维码生成工具_未来码匠的博客-爱代码爱编程

效果图 生成二维码有两种:有图标和无图标,如下图所示:  用微信APP来扫描二维码后,显示解析出的内容,如下图所示: 介绍 ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。基于Java的二维码生成工具,支持自定义二维

spring @valid @validated实现验证的方法_golang.fmt的博客-爱代码爱编程

小编给大家分享一下Spring @Valid @Validated实现验证的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! 对于属性的验证有如下一些注解 @NotBlank:只用在String上,值不能为null,并且trim后长度大于零。不为null,不是全为空格的字符串

[spring学习]5、bean的后置处理器(beanpostprocessor)_bean后置处理器-爱代码爱编程

目录 前言 基本说明 BeanPostProcessor的基本使用 实例应用 总结 前言         在这篇文章中,将会介绍bean的后置处理器,由于这个涉及到AOP的思想,这里不进行过多的深入,也就是不讲原理(后面文章会手写源码),这里只介绍后置处理器如何使用。 基本说明         在spring中,后置处理器会在be