当前位置: 首页 > news >正文

Spring核心--Bean后处理器

Spring的后处理器(Spring核心重点)

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

​ · BeanFactoryPostProcessor: Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行

​ · BeanPostProcessor: Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。

Bean工厂后处理器 – BeanFactoryPostProcessor

BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

BeanFactoryPostProcessor 定义如:

public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}

编写BeanFactoryPostProcessor

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{System.out.println("MyBeanFactoryPostProcessor执行了...");}
}

配置BeanFactoryPostProcessor

<bean class="com.itheima.processor.MyBeanFactoryPostProcessor"/>

postProcessBeanFactory 参数本质就是 DefaultListableBeanFactory,拿到BeanFactory的引用,自然就可以对beanDefinitionMap中的BeanDefinition进行操作了 ,例如对UserDaoImpl的BeanDefinition进行修改操作

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition userDaoBD = beanFactory.getBeanDefinition(“userDao”);//获得UserDao定义对象userDaoBD.setBeanClassName("com.itheima.dao.impl.UserDaoImpl2"); //修改class//userDaoBD.setInitMethodName(methodName); //修改初始化方法//userDaoBD.setLazyInit(true); //修改是否懒加载//... 省略其他的设置方式 ...}
}

上面已经对指定的BeanDefinition进行了修改操作,下面对BeanDefiition进行注册操作

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {//强转成子类DefaultListableBeanFactoryif(configurableListableBeanFactory instanceof DefaultListableBeanFactory){DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");//进行注册操作beanFactory.registerBeanDefinition("userDao2",beanDefinition);}}
}

Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");beanDefinitionRegistry.registerBeanDefinition("userDao2",beanDefinition);}
}

使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描

1.自定义@MyComponent注解,使用在类上

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {//显示的指定Bean的beanNameString value() default "";
}

2.在类上使用@MyComponent

@MyComponent("otherBean")
public class OtherBean {
}

3.自定义BeanFactoryPostProcessor完成注解解析

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//指定要扫描的包String basePackage = "com.itheima";//调用扫描工具扫描指定包及其子包下的@MyComponentMap<String, Class> myComponentClassMap = BaseClassScanUtils.scanMyComponentAnnotation(basePackage);//遍历Map集合,创建BeanDefinition对象进行注册myComponentClassMap.forEach((beanName,clazz)->{try {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(clazz.getName());registry.registerBeanDefinition(beanName,beanDefinition);} catch (Exception e) {e.printStackTrace();}});}

BeanFactoryPostProcessor 在SpringBean的实例化过程中的体现

在这里插入图片描述

Bean后处理器 – BeanPostProcessor

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。

BeanPostProcessor的接口定义如下:

public interface BeanPostProcessor {@Nullable//在属性注入完毕,init初始化方法执行之前被回调default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullable//在初始化方法执行之后,被添加到单例池singletonObjects之前被回调default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

自定义MyBeanPostProcessor,完成快速入门测试

public class MyBeanPostProcessor implements BeanPostProcessor {/* 参数: bean是当前被实例化的Bean,beanName是当前Bean实例在容器中的名称
返回值:当前Bean实例对象 */public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的before方法...");return bean;}/* 参数: bean是当前被实例化的Bean,beanName是当前Bean实例在容器中的名称
返回值:当前Bean实例对象 */public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的after方法...");return bean;}
}

配置MyBeanPostProcessor

<bean class="com.itheima.processors.MyBeanPostProcessor"></bean>

测试控制台打印结果如下:

UserDaoImpl创建了...
UserDaoImpl属性填充...
BeanPostProcessor的before方法...
UserDaoImpl初始化方法执行...
BeanPostProcessor的after方法...

编写BeanPostProcessor,增强逻辑编写在 after方法中

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//对Bean进行动态代理,返回的是Proxy代理对象Object proxyBean = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {long start = System.currentTimeMillis();System.out.println("开始时间:" + new Date(start));//执行目标方法Object result = method.invoke(bean, args);long end = System.currentTimeMillis();System.out.println("结束时间:" + new Date(end));return result;});//返回代理对象return proxyBean;
}

对Bean方法进行执行时间日志增强

编写BeanPostProcessor,增强逻辑编写在 after方法中

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//对Bean进行动态代理,返回的是Proxy代理对象Object proxyBean = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {long start = System.currentTimeMillis();System.out.println("开始时间:" + new Date(start));//执行目标方法Object result = method.invoke(bean, args);long end = System.currentTimeMillis();System.out.println("结束时间:" + new Date(end));return result;});//返回代理对象return proxyBean;
}

BeanPostProcessor 在 SpringBean的实例化过程中的体现

在这里插入图片描述

http://www.lryc.cn/news/504127.html

相关文章:

  • Windows子系统Ubuntu本地部署xinference以及接入dify详解
  • 如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?
  • VR虚拟展厅的实时互动是如何实现的?
  • Java、鸿蒙与嵌入式开发:技术选择与职业发展分析
  • 28. Three.js案例-创建圆角矩形并进行拉伸
  • Shopee算法分析 - x-sap-ri
  • 日志相关的学习记录
  • HTML和JavaScript实现商品购物系统
  • 深度学习中的激活函数
  • 编写php项目所需环境
  • 华为机试HJ108 求最小公倍数
  • 【Python技术】同花顺wencai涨停分析基础上增加连板分析
  • 《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五)
  • 【LeetCode】3356、零数组变换 II
  • Vue 子组件修改父组件传过来的值的三种方式
  • 4.Python 数字类型
  • MacOs 日常故障排除troubleshooting
  • (补)算法刷题Day19:BM55 没有重复项数字的全排列
  • golang中的值传递与引用传递,如何理解结构体的方法?
  • linux部署ansible自动化运维
  • docker—私有仓库搭建
  • 【SpringAOP】深入浅出SpringAOP从原理到源码
  • Java 从查询超时到性能提升 (实战讲解)
  • 《C 语言携手 PaddlePaddle C++ API:开启深度学习开发新征程》
  • Mysql之存储过程
  • XV6 开发环境搭建
  • Windows 系统下 Python 环境安装
  • VMware Workstation的有线连接消失了
  • 73页车企大数据平台规划与数据价值挖掘应用咨询项目方案解读
  • MIF格式详解,javascript加载导出 MIF文件示例