Spring中常见的BeanFactory后处理器

常见的BeanFacatory后处理器

先给出没有添加任何BeanFactory后处理器的测试代码

public class TestBeanFactoryPostProcessor {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}context.close();}
}

在配置类中我们编写了如下信息

@Configuration
@ComponentScan("com.zmt.test5")
public class Config {@Beanpublic Bean2 bean2(){return new Bean2();}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;}@Beanpublic DruidDataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("123456");return dataSource;}
}

同时还有一个Bean1添加了@Component注解并且能够被扫描到,所以理论上来讲,我们可以观察到五个beanName,那么执行测试代码观察输出结果

可以看到,这里只输出了一个beanName,我们可以推测出其他注解没有生效,那么接下来我们将常用的BeanFactory后处理器也注册到BeanFactory后,观察输出结果

public class TestBeanFactoryPostProcessor {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);//添加BeanFactory后处理器context.registerBean(ConfigurationClassPostProcessor.class);//用来解析 @ComponentScan @Bean @Import @ImportResource注解context.registerBean(MapperScannerConfigurer.class,bd -> {bd.getPropertyValues().add("basePackage","com.zmt.test.mapper");});//扫描Mapper,相当于@MapperScan注解context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}context.close();}
}

添加Spring提供的BeanFactory后处理器之后,可以正常将Bean对象添加到context容器当中了,执行结果如下

接下来我们模拟实现在BeanFactory后处理器当中具体如何解析这些注解。 

模拟实现组件扫描

首先是模拟实现@ComponentScan注解是如何扫描包,获取类资源的

public class TestBeanFactoryPostProcessor {public static void main(String[] args) throws IOException {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);//模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);if (componentScan != null) {for (String s : componentScan.basePackages()) {//将com.zmt.test5.bean转化格式为classpath*:com/zmt/test5/bean/**/*.classString path = "classpath*:"+s.replace(".", "/")+"/**/*.class";//创建出一个元数据读取工厂,用来读取类资源信息CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();//通过getResource方法获取到path中的所有类资源Resource[] resources = context.getResources(path);for (Resource resource : resources) {//读取类资源信息MetadataReader reader = factory.getMetadataReader(resource);System.out.println("类名:"+reader.getClassMetadata());System.out.println("是否添加了@Component注解:"+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));System.out.println("是否添加了@Component的派生注解:"+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));}}}context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}context.close();}
}

运行结果如下,可以正常识别类上是否添加了@Component注解或是派生注解

能够扫描到类上添加的注解之后,我们是需要将注解添加到BeanDefinitionMap当中去的,那么继续完善我们的测试方法

public class TestBeanFactoryPostProcessor {public static void main(String[] args) throws IOException {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);//模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);if (componentScan != null) {for (String s : componentScan.basePackages()) {//将com.zmt.test5转化格式为classpath*:com/zmt/test5/**/*.classString path = "classpath*:" + s.replace(".", "/") + "/**/*.class";//创建出一个元数据读取工厂,用来读取类资源信息CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();//通过getResource方法获取到path中的所有类资源Resource[] resources = context.getResources(path);//创建Bean名称生成器AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();for (Resource resource : resources) {//读取类资源信息MetadataReader reader = factory.getMetadataReader(resource);System.out.println("类名1:" + reader.getClassMetadata());AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();System.out.println("是否添加了@Component注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));System.out.println("是否添加了@Component的派生注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));if (annotationMetadata.hasAnnotation(Component.class.getName()) ||annotationMetadata.hasMetaAnnotation(Component.class.getName())) {//如果该类添加了注解,需要添加到BeanDefinitionMap当中去,生成BeanDefinition对象AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();//生成Bean名称String name = generator.generateBeanName(bd,beanFactory);System.out.println("name:"+name);//将BeanDefinition注册到beanFactorybeanFactory.registerBeanDefinition(name,bd);}}}}context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}context.close();}
}

我们通过打断点查看beanFactory中是否将BeanDefinition信息注册到BeanDefinitionMap当中去,结果如下

至此已经实现了组件扫描,但是目前我们的实现是在容器初始化 [refresh()方法] 之前就做好了,我们应该将这些实现抽取到一个BeanFactory后处理器当中,等待refresh()方法回调,因此我们将这些实现代码放入一个组件扫描后处理器。

public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {@Override //在执行context.refresh()方法时回调该方法public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {try {ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);if (componentScan != null) {for (String s : componentScan.basePackages()) {//将com.zmt.test5转化格式为classpath*:com/zmt/test5/**/*.classString path = "classpath*:" + s.replace(".", "/") + "/**/*.class";//创建出一个元数据读取工厂,用来读取类资源信息CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();//通过getResource方法获取到path中的所有类资源Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);//创建Bean名称生成器AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();for (Resource resource : resources) {//读取类资源信息MetadataReader reader = factory.getMetadataReader(resource);System.out.println("类名1:" + reader.getClassMetadata());AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();System.out.println("是否添加了@Component注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));System.out.println("是否添加了@Component的派生注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));if (annotationMetadata.hasAnnotation(Component.class.getName()) ||annotationMetadata.hasMetaAnnotation(Component.class.getName())) {//如果该类添加了注解,需要添加到BeanDefinitionMap当中去,生成BeanDefinition对象AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();if (configurableListableBeanFactory instanceof DefaultListableBeanFactory){DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;String name = generator.generateBeanName(bd,beanFactory);System.out.println("name:"+name);beanFactory.registerBeanDefinition(name,bd);}}}}}} catch (IOException e) {e.printStackTrace();}}
}

修改此时的测试代码,将我们自定义的BeanFactory后处理器注册到context当中 

public class TestBeanFactoryPostProcessor {public static void main(String[] args) throws IOException {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);//模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解context.registerBean(ComponentScanPostProcessor.class);context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}context.close();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/579422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA复习三——CH5 Java Collection 、CH6 MultiThread

CH5 Java Collection(集合) 5.1 Java集合框架(位于java.util包中) 图一 集合框架图 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集…

信息犯罪与计算机取证

1.信息安全 信息安全的三种定义p2 ISO的 为数据处理系统建立和采取的技术和管理的安全保护,保护计算机硬件,软件数据不因偶尔或恶意的原因而受到破坏,更改和泄露 欧盟的 在既定的密级条件下,网络与信息系统抵御意外或恶意行为的能…

【C++】const 关键字

想要正确理解const关键字,只需记住一句话: cosnt关键字优先修饰左边,如果左边每东西,就作用于右边。 const int a; 修饰int a 不能改变 const int *a ; int const *a; 修饰int 指针a指向的地址可以改变,但是地址中…

flask文件夹列表改进版--Bug追踪

把当前文件夹下的所有文件夹和文件列出来,允许点击返回上层目录,允许点击文件夹进入下级目录并显示此文件夹内容 允许点击文件进行下载 from flask import Flask, render_template, send_file, request, redirect, url_for import osapp Flask(__name_…

抖店只能做和营业执照对照的产品吗?开店基础教程,新手可收藏!

我是王路飞。 抖店的营业执照有多重要呢?关系到你店铺的类型、类目和产品。 尤其是适合新手做的个体店,不涉及对公账户,货款可以直接提现到你的私人银行卡里,保证金也只有企业店铺的一半。 (只需要身份证就能开通的…

深入Apache Commons Config:管理和使用配置文件

第1章:引言 咱们都知道,在软件开发中,管理配置文件是一件既重要又让人头疼的事。想象一下,咱们的应用程序有一堆设置需要调整,比如数据库的连接信息、应用的端口号,或者是一些功能的开关。如果这些信息硬编…

uni-app 命令行创建

1. 首先创建项目,命令如下: npx degit dcloudio/uni-preset-vue#vite-ts uni-app-demo如果出现报错,如下图. 大概率就是没有目录C:\Users\Administrator\AppData\Roaming\npm 解决办法: 创建目录 C:\Users\Administrator\AppData\Roaming\n…

基于nodemailer实现邮件发送、附件发送、多人发送

文章目录 1、QQ邮箱如何设置授权码2、具体代码 1、QQ邮箱如何设置授权码 QQ邮箱SMTP/IMAP服务 1、点击账号与安全 2、安全设置 3、设备管理&#xff0c;可以查看有多少个授权码 2、具体代码 from 这个参数&#xff0c;有两种写法 qq号qq.com"姓名"<qq号qq.co…

UDP Ping程序实现--第5关:客户端向服务器发送消息并接收消息

✨创作不易&#xff0c;还希望各位大佬支持一下 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你的青睐是我努力的方向&#xff01; ✏️ 评论&#xff0c;你的意见是我进步的财富&#xff01; 任务描述 本关任务&#xff1a;P…

【数据库系统概论】第3章-关系数据库标准语言SQL(2)

文章目录 3.4 数据查询3.4.1 单表查询3.4.2 连接查询3.4.3嵌套查询3.4.4 集合查询3.4.5 基于派生表的查询3.4.6 select 语句的目标列 3.4 数据查询 格式 SQL执行顺序 3.4.1 单表查询 基础查询 select * from student // 不重复 select distinct sname from student // 命名…

C++ Lambda表达式的完整介绍

c在c11标准中引入了lambda表达式&#xff0c;一般用于定义匿名函数&#xff0c;使得代码更加灵活简洁。lambda表达式与普通函数类似&#xff0c;也有参数列表、返回值类型和函数体&#xff0c;只是它的定义方式更简洁&#xff0c;并且可以在函数内部定义。 什么是Lambda表达式…

【番外】在Windows安装Airsim/UE4踩坑合集

在Windows安装Airsim/UE4踩坑合集 1.安装过程中一定要确保Epic Games Launcher是英文环境&#xff0c;保存路径什么的也尽量是英文。2.UE4中的虚幻引擎一定要安装4.27版本以上的&#xff0c;不然的话最后运行vs的时候会报语法错误&#xff0c;网上根本查不到的那种错误。换了版…

谷歌被曝或再次大裁员!3万员工面临被AI取代

据报道&#xff0c;继1.2万大裁员之后&#xff0c;谷歌又计划重组广告销售部门——这将导致3万名员工面临裁员的风险。 这一年的科技行业&#xff0c;可以说是从年头裁到了年尾&#xff0c;还越裁越多了。 而这次谷歌的部门重组计划&#xff0c;让打工人们发现&#xff0c;除…

【Vulnhub 靶场】【Funbox: Scriptkiddie】【非常简单】【20210720】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/funbox-scriptkiddie,725/ 靶场下载&#xff1a;https://download.vulnhub.com/funbox/Funbox11.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年07月20日 文件大小&#xff1a;1.3 GB 靶场作者&…

盘古信息IMS-MOM制造运营管理系统,构建生产现场管理信息系统的最佳选择

在当今高度竞争的制造行业中&#xff0c;高效的生产管理是企业成功的关键。盘古信息IMS-MOM制造运营管理系统作为一款领先的管理系统其关键特性为制造企业构建生产现场管理信息系统提供了强大的优势。IMS-MOM不仅仅是一个软件系统&#xff0c;更是一种技术和管理手段的结合&…

【Kafka】Kafka客户端认证失败:Cluster authorization failed.

背景 kafka客户端是公司内部基于spring-kafka封装的spring-boot版本&#xff1a;3.xspring-kafka版本&#xff1a;2.1.11.RELEASE集群认证方式&#xff1a;SASL_PLAINTEXT/SCRAM-SHA-512经过多年的经验&#xff0c;以及实际验证&#xff0c;配置是没问题的&#xff0c;但是业务…

Java-Maven3.9.6:Maven依赖管理 / 安装-配置-使用

一、理解Maven Maven是一个开源的项目管理工具&#xff0c;主要用于构建和管理Java项目、依赖管理和文档生成&#xff0c;它可以自动下载所需的依赖库&#xff0c;并自动构建整个项目。理解Maven需要了解以下几个方面&#xff1a; 1. 项目对象模型&#xff08;Project Object…

7.2 uvm_resource_db in UVM

uvm_resource_db是一个类型参数化 type-parameterized的类&#xff0c;它是资源数据库顶部的一个方便层(convenience layer)。这个便利层简化了对低级数据库的访问&#xff0c;并且没有添加新功能。因此&#xff0c;uvm_resource_db不是从uvm_resource类派生的。以下uvm_resour…

Scala安装

Scala安装使用 windows安装,配置环境变量 以下载Scala2.11为例&#xff0c;操作在Windows中安装Scala。 官网下载scala2.11&#xff1a;All Available Versions | The Scala Programming Language下载好后安装。双击msi包安装,记住安装的路径。配置环境变量&#xff08;和配…

mvtec3d

以bagel为例&#xff0c;其中有calibration、 bagel # 百吉圈(硬面包)calibrationcamera_parameters.jsontestcombinedgt # 缺陷部位的分割剪影pngrgb # 原图pngxyz # tiffcontamination # 污染物同上crack同上good同上 hole同上 traingoodrgbxyzvalidationgood同traincla…