实现BeanPostProcessor

2024-08-23 12:44
文章标签 实现 beanpostprocessor

本文主要是介绍实现BeanPostProcessor,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.实现初始化方法
        • 1.目录
        • 2.InitializingBean.java
        • 3.MonsterService.java 实现初始化接口
        • 4.SunSpringApplicationContext.java 调用初始化方法
        • 5.测试
    • 2.实现后置处理器
        • 1.目录
        • 2.BeanPostProcessor.java 后置处理器接口
        • 3.SunBeanProcessor.java 自定义后置处理器
        • 4.SunSpringApplicationContext.java 具体实现
          • 1.定义一个存储后置处理器的List
          • 2.在扫描bean的时候将后置处理器放到List中
          • 3.初始化bean前后使用调用后置处理器进行处理
          • 4.测试
          • 5.完整代码

1.实现初始化方法

1.目录

CleanShot 2024-08-06 at 12.28.31@2x

2.InitializingBean.java
package com.sunxiansheng.sunspring.processor;/*** Description: Bean的初始化接口* @Author sun* @Create 2024/8/5 16:35* @Version 1.0*/
public interface InitializingBean {/*** 在Bean的所有属性设置完成之后调用*/void afterPropertiesSet();}
3.MonsterService.java 实现初始化接口
package com.sunxiansheng.sunspring.compent;import com.sunxiansheng.sunspring.annotation.Component;
import com.sunxiansheng.sunspring.annotation.Resource;
import com.sunxiansheng.sunspring.annotation.Scope;
import com.sunxiansheng.sunspring.annotation.myenum.MyScope;
import com.sunxiansheng.sunspring.processor.InitializingBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** Description: 怪物服务* @Author sun* @Create 2024/8/4 16:31* @Version 1.0*/
// 自定义注解:将MonsterService类交给自定义Spring容器管理
// 如果指定value属性,则使用value属性值作为bean的id,否则使用类名首字母小写作为bean的id
@Component
@Scope(value = MyScope.PROTOTYPE) // 指定bean的作用域为多例
public class MonsterService implements InitializingBean {private static final Logger log = LoggerFactory.getLogger(MonsterService.class);/*** 自定义的Resource注解,用于自动注入MonsterDao对象*/@Resourceprivate MonsterDao monsterDao;public void query() {log.info("MonsterService调用MonsterDao");monsterDao.query();}/*** 初始化方法*/@Overridepublic void afterPropertiesSet() {log.info("MonsterService初始化完成...");}}
4.SunSpringApplicationContext.java 调用初始化方法

CleanShot 2024-08-06 at 12.33.56@2x

5.测试

CleanShot 2024-08-06 at 12.34.18@2x

2.实现后置处理器

1.目录

CleanShot 2024-08-06 at 13.35.31@2x

2.BeanPostProcessor.java 后置处理器接口
package com.sunxiansheng.sunspring.processor;/*** Description: 自定义BeanPostProcessor接口* @Author sun* @Create 2024/8/6 12:36* @Version 1.0*/
public interface BeanPostProcessor {/*** 该方法在bean的初始化方法之前执行* @param bean* @param beanName* @return*/default Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}/*** 该方法在bean的初始化方法之后执行* @param bean* @param beanName* @return*/default Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}}
3.SunBeanProcessor.java 自定义后置处理器
package com.sunxiansheng.sunspring.compent;import com.sunxiansheng.sunspring.annotation.Component;
import com.sunxiansheng.sunspring.processor.BeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** Description:* @Author sun* @Create 2024/8/6 12:39* @Version 1.0*/
@Component
public class SunBeanProcessor implements BeanPostProcessor {private static final Logger log = LoggerFactory.getLogger(SunBeanProcessor.class);@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {log.info("SunBeanProcessor postProcessBeforeInitialization..." + beanName + "=>" + bean.getClass());// 返回空,不对bean进行处理return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {log.info("SunBeanProcessor postProcessAfterInitialization..." + beanName + "=>" + bean.getClass());// 返回空,不对bean进行处理return null;}}
4.SunSpringApplicationContext.java 具体实现
1.定义一个存储后置处理器的List

CleanShot 2024-08-06 at 13.36.53@2x

2.在扫描bean的时候将后置处理器放到List中

CleanShot 2024-08-06 at 13.37.17@2x

3.初始化bean前后使用调用后置处理器进行处理

CleanShot 2024-08-06 at 13.37.53@2x

4.测试

CleanShot 2024-08-06 at 13.38.49@2x

5.完整代码
package com.sunxiansheng.sunspring.ioc;import com.sunxiansheng.sunspring.annotation.Component;
import com.sunxiansheng.sunspring.annotation.ComponentScan;
import com.sunxiansheng.sunspring.annotation.Resource;
import com.sunxiansheng.sunspring.annotation.Scope;
import com.sunxiansheng.sunspring.annotation.myenum.MyScope;
import com.sunxiansheng.sunspring.processor.BeanPostProcessor;
import com.sunxiansheng.sunspring.processor.InitializingBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** Description: 自定义Spring容器* @Author sun* @Create 2024/8/4 16:35* @Version 1.0*/
public class SunSpringApplicationContext {private static final Logger log = LoggerFactory.getLogger(SunSpringApplicationContext.class);/*** bean定义的map*/private ConcurrentHashMap<String, BeanDefintion> beanDefintionMap = new ConcurrentHashMap<>();/*** 单例池*/private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();/*** bean的后置处理器*/private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();// 构造器,接收配置类的class对象public SunSpringApplicationContext(Class<?> configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// 完成bean的扫描,将bean的信息记录到beanDefintionMap中beanDefinitionByScan(configClass);// 初始化单例池initSingletonObjects();}/*** 给某个bean对象完成依赖注入*/private void populateBeans(Object bean) {// 扫描beanDefintionMap中的bean信息,对bean对象中的属性进行依赖注入// 获取Class对象Class<?> clazz = bean.getClass();// 获取所有字段Field[] fields = clazz.getDeclaredFields();// 判断字段上是否有@Resource注解for (Field field : fields) {if (field.isAnnotationPresent(Resource.class)) {// 获取字段名String fieldName = field.getName();// 根据字段名获取bean对象Object beanObject = null;// 从beanDefintionMap中获取bean对象BeanDefintion beanDefintion = beanDefintionMap.get(fieldName);try {// 根据bean的定义信息创建bean对象beanObject = getBean(fieldName);} catch (Exception e) {throw new RuntimeException(e);}// 设置字段可访问field.setAccessible(true);try {// 依赖注入field.set(bean, beanObject);log.info("依赖注入成功:{} => {}.{}", beanObject.getClass(), clazz, fieldName);} catch (IllegalAccessException e) {e.printStackTrace();}}}}/*** 初始化单例池*/private void initSingletonObjects() {// 将beanDefintionMap中的bean信息创建成bean对象放到单例池中beanDefintionMap.forEach((beanName, beanDefintion) -> {try {// 根据bean的定义信息创建bean对象Object bean = createBean(beanDefintion);if (bean != null) {// 将bean对象放到单例池中singletonObjects.put(beanName, bean);}} catch (Exception e) {e.printStackTrace();}});// 打印单例池中的bean对象log.info("根据bean定义信息初始化单例池:{}", singletonObjects);}// 返回容器中的对象public Object getBean(String name) throws Exception {BeanDefintion beanDefintion = beanDefintionMap.get(name);if (beanDefintion == null) {throw new NullPointerException("在bean定义中没有找到bean对象");}// 根据单例和多例来获取bean对象MyScope scope = beanDefintion.getScope();Object bean = null;if (scope == MyScope.SINGLETON) {log.info("getBean单例对象:{}", singletonObjects.get(name));// 单例就直接从单例池中获取对象bean = singletonObjects.get(name);} else {// 多例就创建一个新的对象bean = createProtoTypeBean(beanDefintion);}// 给bean对象完成依赖注入populateBeans(bean);// 记录当前对象,因为后置处理器可能会返回一个新的对象Object current = bean;// 初始化方法之前调用后置处理器 postProcessBeforeInitializationfor (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {Object bean1 = beanPostProcessor.postProcessBeforeInitialization(bean, name);// 如果beanPostProcessor返回的对象为空,则使用原来的对象if (bean1 != null) {current = bean1;}}// 初始化beaninit(current);// 初始化方法之后调用后置处理器 postProcessAfterInitializationfor (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {bean = beanPostProcessor.postProcessAfterInitialization(current, name);// 如果beanPostProcessor返回的对象为空,则使用原来的对象if (bean == null) {bean = current;}}log.info("getBean多例对象:{}", bean);return bean;}/*** 初始化bean* @param bean*/public void init(Object bean) {if (bean instanceof InitializingBean) {((InitializingBean) bean).afterPropertiesSet();}}/*** 根据bean的定义信息创建bean对象(单例bean)* @param beanDefintion* @return* @throws Exception*/private Object createBean(BeanDefintion beanDefintion) throws Exception {// 得到bean的类型Class<?> clazz = beanDefintion.getClazz();// 根据bean的作用域创建bean对象,多例就不创建了,单例就创建if (beanDefintion.getScope() == MyScope.PROTOTYPE) {return null;}Object bean = clazz.getDeclaredConstructor().newInstance();return bean;}/*** 创建多例bean* @param beanDefintion* @return* @throws InstantiationException* @throws IllegalAccessException* @throws InvocationTargetException* @throws NoSuchMethodException*/private static Object createProtoTypeBean(BeanDefintion beanDefintion) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {// 多例就创建一个新的对象Class<?> clazz = beanDefintion.getClazz();Object bean = clazz.getDeclaredConstructor().newInstance();return bean;}/*** 完成bean的扫描,将bean的信息记录到beanDefintionMap中* @param configClass* @throws ClassNotFoundException*/private void beanDefinitionByScan(Class<?> configClass) {// 传进来一个配置类的Class对象// 一、获取要扫描的包// 1.首先反射获取类的注解信息ComponentScan componentScan = configClass.getDeclaredAnnotation(ComponentScan.class);// 2.通过注解来获取要扫描的包的路径String path = componentScan.packagePath();log.info("扫描的包路径:{}", path);// 二、得到要扫描包的.class文件对象,从而得到全路径进行反射// 1.获取App类加载器ClassLoader classLoader = SunSpringApplicationContext.class.getClassLoader();// 2.获取要扫描包的真实路径,默认刚开始在根目录下path = path.replace(".", "/");URL resource = classLoader.getResource(path);// 3.由该路径创建一个文件对象,可使用resource.getFile()将URL类型转化为String类型File file = new File(resource.getFile());// 4.遍历该文件夹下的所有.class文件对象if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) {// 反射注入容器// 1.获取所有文件的绝对路径String absolutePath = f.getAbsolutePath();// 只处理class文件if (absolutePath.endsWith(".class")) {// 2.分割出类名String className = extractClassName(absolutePath);// 3.得到全路径String fullPath = path.replace("/", ".") + "." + className;// 4.判断是否需要注入容器,查看有没有自定义的注解ComponentClass<?> aClass = null;try {aClass = classLoader.loadClass(fullPath);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}// 如果该类使用了注解Component则说明是一个spring beanif (aClass.isAnnotationPresent(Component.class)) {log.info("扫描到Spring Bean:{}", aClass);// 将Bean的后置处理器加入到beanPostProcessorList中// 判断Class对象是否实现了BeanPostProcessor接口if (BeanPostProcessor.class.isAssignableFrom(aClass)) {Object o = null;try {o = aClass.getDeclaredConstructor().newInstance();} catch (Exception e) {log.info("BeanPostProcessor实例化失败:{}", e);}if (o instanceof BeanPostProcessor) {beanPostProcessorList.add((BeanPostProcessor) o);}log.info("BeanPostProcessor实例化成功:{}", o);// 直接跳过,不需要将BeanPostProcessor加入到beanDefintionMap中continue;}// 将bean的信息记录到beanDefintionMap中BeanDefintion beanDefintion = new BeanDefintion();// 1.获取Scope注解的value值if (aClass.isAnnotationPresent(Scope.class)) {Scope scope = aClass.getDeclaredAnnotation(Scope.class);MyScope value = scope.value();// 放到beanDefintion中beanDefintion.setScope(value);} else {// 如果没有指定作用域,则默认为单例beanDefintion.setScope(MyScope.SINGLETON);}beanDefintion.setClazz(aClass);// 2.获取Component注解的value值Component component = aClass.getDeclaredAnnotation(Component.class);String beanName = component.value();if ("".equals(beanName)) {// 如果没有指定value属性,则使用类名首字母小写作为bean的idbeanName = className.substring(0, 1).toLowerCase() + className.substring(1);}// 3.将bean的id和bean的信息放到beanDefintionMap中beanDefintionMap.put(beanName, beanDefintion);} else {log.info("这不是一个Spring Bean={}", aClass);}}}}// 打印beanDefintionMap中的bean信息log.info("将bean定义信息放到beanDefintionMap:{}", beanDefintionMap);}/*** 分割出类名* 类似于 com/sunxiansheng/sunspring/compent/MonsterService.class 的类名* @param filePath* @return*/private String extractClassName(String filePath) {// 获取最后一个 '/' 的位置int lastSlashIndex = filePath.lastIndexOf('/');// 获取最后一个 '.' 的位置int lastDotIndex = filePath.lastIndexOf('.');// 提取两者之间的字符串作为类名return filePath.substring(lastSlashIndex + 1, lastDotIndex);}}

这篇关于实现BeanPostProcessor的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1099417

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机