• Spring后处理器-BeanPostProcessor


    Spring后处理器-BeanPostProcessor

    • Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过bean的初始化过程((该后处理器的执行时机)),例如:属性的填充、初始化方法init的执行等,其中有一个对外拓展的点BeanPostProcessor,我们称之为bean后处理器。与上文bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor(即在配置文件中对其进行配置),会在流程节点上被Spring自动调用。
    • BeanPostProcessor接口代码如下
        1. //
        2. // Source code recreated from a .class file by IntelliJ IDEA
        3. // (powered by FernFlower decompiler)
        4. //
        5. package org.springframework.beans.factory.config;
        6. import org.springframework.beans.BeansException;
        7. import org.springframework.lang.Nullable;
        8. public interface BeanPostProcessor {
        9. @Nullable
        10. default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        11. return bean;
        12. }
        13. @Nullable
        14. default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        15. return bean;
        16. }
        17. }
    • 创建实现该接口(BeanPsotProcessor)的类,要在配置文件中进行管理
      • 快捷键 ctrl + insert 重写接口方法
        1. package com.example.PostProcessor;
        2. import org.springframework.beans.BeansException;
        3. import org.springframework.beans.factory.config.BeanPostProcessor;
        4. public class MyBeanPostProcessor implements BeanPostProcessor {
        5. @Override
        6. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        7. System.out.println(beanName + ":postProcessBeforeInitialization");
        8. return bean;
        9. }
        10. @Override
        11. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        12. System.out.println(beanName + ":postProcessAfterInitialization");
        13. return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
        14. }
        15. }
    • 测试类代码

        1. package com.example.Test;
        2. import com.example.Service.Impl.UserServiceImpl;
        3. import org.springframework.context.support.ClassPathXmlApplicationContext;
        4. public class TestApplicationContext {
        5. public static void main(String[] args) {
        6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        7. System.out.println(context.getBean(UserServiceImpl.class));
        8. }
        9. }
    • 运行结果如下


      •  

      • 展示了该后处理器的执行时机 


    Before和After执行时机

    • 在Bean实例化过程可以配置相关对于bean对象的操作方法,具体间往期文章:Bean的配置- CSDN搜索
    • 注册为bean的类
        1. package com.example.Service.Impl;
        2. import com.example.DAO.UserDAO;
        3. import com.example.Service.UserService;
        4. import org.springframework.beans.factory.InitializingBean;
        5. import java.util.List;
        6. import java.util.Map;
        7. import java.util.Set;
        8. public class UserServiceImpl implements UserService, InitializingBean {
        9. // todo 无参构造方法
        10. public UserServiceImpl() {
        11. System.out.println("UserServiceImpl实例化");
        12. }
        13. // todo 自定义初始化方法
        14. public void init() {
        15. System.out.println("自定义初始化方法init()");
        16. }
        17. @Override
        18. public void afterPropertiesSet() throws Exception {
        19. System.out.println("属性设置之后执行afterPropertiesSet()");
        20. }
        21. }
    • 实现bean后处理器的类
        1. package com.example.PostProcessor;
        2. import org.springframework.beans.BeansException;
        3. import org.springframework.beans.factory.config.BeanPostProcessor;
        4. public class MyBeanPostProcessor implements BeanPostProcessor {
        5. @Override
        6. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        7. System.out.println(beanName + ":postProcessBeforeInitialization");
        8. return bean;
        9. }
        10. @Override
        11. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        12. System.out.println(beanName + ":postProcessAfterInitialization");
        13. return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
        14. }
        15. }
    • 配置文件

        1. "1.0" encoding="UTF-8"?>
        2. <beans xmlns="http://www.springframework.org/schema/beans"
        3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
        4. xmlns:context="http://www.springframework.org/schema/context"
        5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
        6. <bean class="com.example.PostProcessor.MyBeanPostProcessor">bean>
        7. <bean id="userService" class="com.example.Service.Impl.UserServiceImpl" init-method="init">
        8. beans>
    • 测试类

        1. package com.example.Test;
        2. import com.example.Service.Impl.UserServiceImpl;
        3. import org.springframework.context.support.ClassPathXmlApplicationContext;
        4. public class TestApplicationContext {
        5. public static void main(String[] args) {
        6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        7. System.out.println(context.getBean(UserServiceImpl.class));
        8. }
        9. }
    • 运行结果

    小结 

    • 从上述运行结果来看,首先完成bean对象的创建,然后执行后处理器中的before方法,然后执行属性设置之后的方法,然后执行自定义的初始化方法,最后执行后处理器的after方法

    案例

    • 对Bean方法进行执行时间日志增强
    • 要求
      • Bean的方法执行之前控制台打印当前时间
      • Bean的方法执行之后控制台打印当前时间
    • 分析
      • 对方法进行增强主要就是代理设计模式和包装设计模式
      • 由于Bean方法不确定,所以使用动态代理在运行期间执行增强操作
      • 在Bean实例创建完毕之后,进入到单例之前,使用Proxy真实的目标bean
    • 具体代码如下
      • 代理类(实现了bean后处理接口)
        1. package com.example.PostProcessor;
        2. import org.springframework.beans.BeansException;
        3. import org.springframework.beans.factory.config.BeanPostProcessor;
        4. import java.lang.reflect.InvocationHandler;
        5. import java.lang.reflect.Proxy;
        6. import java.util.Date;
        7. public class TimeLogBeanPostProcessor implements BeanPostProcessor {
        8. @Override
        9. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        10. // todo 使用动态代理对目标bean进行增强,返回proxy对象,进而存储到单例池singletonObjects中
        11. Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (InvocationHandler) (proxy, method, args) -> {
        12. // 输出开始时间
        13. System.out.println("方法" + method.getName() + "开始执行时间" + new Date());
        14. // 执行目标方法
        15. Object rs = method.invoke(bean, args);
        16. // 输出结束时间
        17. System.out.println("方法" + method.getName() + "结束执行时间" + new Date());
        18. return rs;
        19. });
        20. return beanProxy;// 将增强的bean存入单例池中
        21. }
        22. }
      • bean对象对应的类

        1. package com.example.Service.Impl;
        2. import com.example.Service.UserService;
        3. public class UserServiceImpl implements UserService {
        4. public void show() {
        5. System.out.println("show......");
        6. }
        7. }
      • 接口类

        1. package com.example.Service;
        2. public interface UserService {
        3. public void show();
        4. }
      • 配置文件

        1. "1.0" encoding="UTF-8"?>
        2. <beans xmlns="http://www.springframework.org/schema/beans"
        3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        5. <bean class="com.example.PostProcessor.TimeLogBeanPostProcessor">bean>
        6. <bean id="userService" class="com.example.Service.Impl.UserServiceImpl">
        7. bean>
        8. beans>
      • 测试类

        1. package com.example.Test;
        2. import com.example.Service.UserService;
        3. import org.springframework.context.support.ClassPathXmlApplicationContext;
        4. public class TestApplicationContext {
        5. public static void main(String[] args) {
        6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        7. UserService UserServiceBean = (UserService) context.getBean(UserService.class);
        8. UserServiceBean.show();
        9. }
        10. }
      • 运行结果

    Bean实例化基本流程图



    • 首先通过Reader读取配置文件,解析bean标签,然后将每个bean标签变成beanDefinition对象存储到beanDefinitionMap中,然后经过所有的BeanFactoryPostProcessor(bean工厂后处理器),再从Map中取出每个beanDefiniton对象,通过反射变成Object对象,创建完对象后,经过beanPoatProcessor中的before方法和after方法(之间还存在bean中的init方法,后面会讲述),最终存入单例池中。 

    在学习本文章内容的时候,我也去补充了一下,基础知识,便于更加程序运行原理,具体文章如下

    Java高级-代理(proxy)_熵240的博客-CSDN博客
    Java高级-注解_熵240的博客-CSDN博客
    反射的作用、应用场景_熵240的博客-CSDN博客
    Java高级-反射_熵240的博客-CSDN博客
    Lambda表达式_熵240的博客-CSDN博客

  • 相关阅读:
    内存卡视频误删怎么恢复?4个方法,找回视频!
    让数据“动”起来:Python动态图表制作详解
    MySQL高级语句(三)——存储过程
    [MQ] 交换机与队列的介绍
    纯手撸一个神经网络(只用numpy识别mnist数据集,全代码)
    Dapr 的 gRPC组件(又叫可插拔组件)的提案
    matlab中filter帮助文档中“对矩阵行进行滤波”的解释
    Kotlin挂起函数基础
    Swarm集群负载均衡的实现方式
    IoT 边缘集群基于 Kubernetes Events 的告警通知实现
  • 原文地址:https://blog.csdn.net/weixin_64939936/article/details/133130595