Spring Bean定义有哪些方式?
概述
对于学习Spring的兄弟姐妹来说,觉得这个问题很熟悉,若是要把它回答得很清楚,却是很为难?平时写代码的时候,不会在意这些概念问题,但面试时这个问题出现的频率却是很高,所以还是必须要掌握和理解。
Spring Bean定义有哪些方式?
总的来说,分三种:
1)基于xml的方式
2)基于注解的方式
3)基于java类的方式
1、基于xml的方式
XML配置的方式,是Spring最早支持的方式,不过现在XML方式已经用的比较少了,基本上都是用后面的配置方式替代了。
示例:
@Data
@ToString
public class Student {String name;int age;
}
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="student" class="com.koo.entity.Student"/>
</beans>
public class Client {public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");System.out.println(applicationContext.getBean("student"));}
}
2、基于注解的方式
又分一下几种方式
1) 使用@Component注解 + @ComponentScan包扫描方式
2)@Configuration + @Bean方式
3)FactoryBean方式
4)@Import方式
5)@Import + ImportSelector方式
6)@Import + ImportBeanDefinitionRegistrar方式
7)BeanDefinitionRegistryPostProcessor方式
8)BeanFactoryPostProcessor方式
1) 使用@Component注解 + @ComponentScan包扫描方式
为了解决bean太多时,XML文件过大,从而导致膨胀不好维护的问题。在Spring2.5中开始支持:
@Component、@Repository、@Service、@Controller等注解定义bean。@Component放在类名上面,然后通过@ComponentScan指定一个路径,Spring进行扫描带有@Componet注解的bean,然后加至容器中。
@Component
public class UserHandler {
}
@Service
public class UserService {
}
@Repository
public class UserDao {
}
@Controller
public class UserController {
}
@ComponentScan("com.koo.modules")
@Configuration
public class AppConfig {
}
/*** 通常情况下: ** @Controller:一般用在控制层* @Service:一般用在业务层* @Repository:一般用在持久层* @Component:一般用在公共组件上*/
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("userDao"));System.out.println(applicationContext.getBean("userService"));System.out.println(applicationContext.getBean("userController"));System.out.println(applicationContext.getBean("userHandler"));}
}
2)@Configuration + @Bean方式
这种方式其实也是我们最常用的方式之一,@Configuration用来声明一个配置类,然后使用 @Bean 注解声明一个bean,将其加入到Spring容器中。通常情况下,如果项目中有使用到第三方类库中的工具类的话,我们都是采用这种方式注册Bean。
示例代码:
public class Student {
}
@Configuration
public class AppConfig {@Beanpublic Student student() {return new Student();}}
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("student"));}
}
3)FactoryBean方式
FactoryBean是一个Bean,它允许我们自定义Bean的创建,主要有三个方法:
1、getObject():自定义Bean如何创建;
2、getObjectType():要注册的Bean的类型;
3、isSingleton():是否单例;
示例代码:
public class User {
}
@Component
public class UserFactoryBean implements FactoryBean<User> {@Overridepublic User getObject() throws Exception {return new User();}@Overridepublic Class<?> getObjectType() {return User.class;}@Overridepublic boolean isSingleton() {return true;}
}
@Configuration
@ComponentScan("com.koo. modules")
public class AppConfig {}
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("userFactoryBean"));System.out.println(applicationContext.getBean("&userFactoryBean"));}
}
4)@Import方式
public class Student {
}
@Import({Student.class})
@Configuration
public class AppConfig {}
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}System.out.println("================");System.out.println(applicationContext.getBean("com.koo.modules.entity.Student"));System.out.println(applicationContext.getBean("student"));}
}
5)@Import + ImportSelector方式
首先介绍一下ImportSelector接口的好处,主要有以下两点:
1、把某个功能的相关类放到一起,方面管理和维护。
2、重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等,我们能够非常灵活的定制化bean的实例化。
public class Product {
}
public class User {
}
public class MyImportSelector implements ImportSelector {// 指定需要定义bean的类名,注意要包含完整路径,而非相对路径@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.koo.entity.Product", "com.koo.entity.User"};}}
@Import({MyImportSelector.class})
@Configuration
public class AppConfig {
}
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);} System.out.println(applicationContext.getBean("com.koo.entity.Product"));try {System.out.println(applicationContext.getBean("product"));} catch (Exception e) {e.printStackTrace();} System.out.println(applicationContext.getBean("com.koo.entity.User"));try {System.out.println(applicationContext.getBean("user"));} catch (Exception e) {e.printStackTrace();}}
}
6)@Import + ImportBeanDefinitionRegistrar方式
这种方式我们需要实现ImportBeanDefinitionRegistrar接口,并重写registerBeanDefinitions()方法,然后定义我们需要注册的Bean的定义信息,然后registry.registerBeanDefinition()方法注册即可。这种方式比ImportSelector更加灵活,可以自定义bean的名称、作用域等很多参数。 像我们常见的Spring Cloud中的Feign,就使用了ImportBeanDefinitionRegistrar,具体可以参考FeignClientsRegistrar类
public class User {
}public class Product {
}public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 可以自定义bean的名称、作用域等很多参数registry.registerBeanDefinition("user", new RootBeanDefinition(User.class));RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Product.class);rootBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);registry.registerBeanDefinition("product", rootBeanDefinition);}
}@Import({CustomImportBeanDefinitionRegistrar.class})
@Configuration
public class AppConfig {}public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("product"));System.out.println(applicationContext.getBean("user"));}
}
7)BeanDefinitionRegistryPostProcessor方式
在Spring容器启动方法refresh()方法的invokeBeanFactoryPostProcessors()方法中,会执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry()方法,它允许对beanDefinition进行后置处理,我们可以在这个方法调整IOC容器中的beanDefinition定义信息,从而干扰到后面bean初始化的过程。
具体代码如下:
public class User {
}@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {registry.registerBeanDefinition("user", new RootBeanDefinition(User.class));}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}@Configuration
@ComponentScan("com.koo.modules")
public class AppConfig {}public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("user"));}
}
8)BeanFactoryPostProcessor方式
其实BeanDefinitionRegistryPostProcessor就是继承自BeanFactoryPostProcessor,所以使用BeanFactoryPostProcessor也可以实现注册Bean的功能。它们的区别如下:
1、 BeanDefinitionRegistryPostProcessor:侧重于bean的注册;
2、 BeanFactoryPostProcessor:侧重于对已经注册的bean的属性进行修改,虽然也可以注册bean;
public class Product {
}@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {DefaultListableBeanFactory registry = (DefaultListableBeanFactory) beanFactory;registry.registerBeanDefinition("product", new RootBeanDefinition(Product.class));}
}@Configuration
@ComponentScan("com.koo.modules")
public class AppConfig {}public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(applicationContext.getBean("product"));}
}
3、基于Java类的方式
1.使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
2.使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
3.AnnotationConfigApplicationContext或子类进行加载基于java类的配置
@Configuration
public class BeansConfiguration { @Bean public Student student(){ Student student=new Student(); student.setName("张三"); student.setTeacher(teacher()); return student; } @Bean public Teacher teacher(){ Teacher teacher=new Teacher(); teacher.setName("李四"); return teacher; }
}
public class Client{ public static void main(String args[]){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeansConfiguration.class); Student student = (Student) context.getBean("student");Teacher teacher = (Teacher) context.getBean("teacher");System.out.println("学生的姓名:" + student.getName() + "。老师是" + student.getTeacher().getName()); System.out.println("老师的姓名:" + teacher.getName()); } }
示例源码:https://gitee.com/charlinchenlin/koo-erp
相关文章:
Spring Bean定义有哪些方式?
概述 对于学习Spring的兄弟姐妹来说,觉得这个问题很熟悉,若是要把它回答得很清楚,却是很为难?平时写代码的时候,不会在意这些概念问题,但面试时这个问题出现的频率却是很高,所以还是必须要掌握…...
JVM内存模型的演变
1,背景 class文件、类的加载过程。我们的class文件就要进入到JVM内存里,我们沿着经典的JDK1.6,JDK1.7,JDK1.8看看在其中都经历了哪些改变 概念的统一: 方法区: 方法区可以看作是JVM逻辑上管理一片区域的…...
DataX3同步Mysql数据库数据到Mysql数据库和DataX3同步mysql数据库数据到Starrocks数据库
DataX3同步Mysql数据库数据到Mysql数据库和DataX3同步mysql数据库数据到Starrocks 一、认识DataX二、DataX3概览三、DataX3框架设计四、DataX3插件体系五、DataX3核心架构六、DataX 3六大核心优势1.可靠的数据质量监控2.丰富的数据转换功能3.精准的速度控制4.强劲的同步性能5.健…...
你是否曾经为自己写的代码而感到懊恼?那如何才能写出高质量代码呢?
这里写目录标题 一、 前言二、高质量代码的特征三、编程实践技巧1. 遵循编码规范2. 使用有意义的变量名和函数名3. 减少代码重复4. 使用注释5. 编写单元测试6. 使用设计模式7. 使用版本控制工具8. 保持代码简洁9. 优化代码性能10. 学习和借鉴他人的代码总结 一、 前言 写出高质…...
常用 Composition API【VUE3】
二、常用 Composition API 7. 计算属性与监视 7.1 computed函数 与Vue2.x中computed配置功能一致写法 <template><h1>一个人的信息</h1>姓:<input type"text" v-model"person.firstName"><br><br>名&a…...
--商业模式--
O2O O2O,网络用语中指Online To Offline的缩写,即在线离线/线上到线下,是指将线下的商务机会与互联网结合,让互联网成为线下交易的平台。 O2O概念最早来源于美国。O2O的概念非常广泛,既可涉及到线上,又可…...
JavaWeb《HTML基础标签》
本笔记学习于Acwing平台 MDN官方文档https://developer.mozilla.org/zh-CN/ 目录 1. html文件结构 2. 文本标签 3. 图片 4. 音频和视频 5. 超链接 6. 表单 7. 列表 8. 表格 9. 语义标签 10. 特殊符号 1. html文件结构 文档结构 html的所有标签为树形结构ÿ…...
ChatGpt 能取代人类吗?
目录 前言 一、ChatGpt是什么? 二、ChatGpt能做什么 总结 前言 随着人工智能的不断发展,很多人都开启了学习机器学习,以及现在ChatGpt的出现,对人类社会带来了很多变化。 智能化交流方式:ChatGpt的出现为人们提供了…...
PHP内存溢出Allowed memory size of 解决办法
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法 .于是写小文一篇总结一下. PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to allocate xxx bytes) 不想看原理的,直接跳到最后…...
重回代码,学习总结
回顾加总结 2021年 自动化测试 1.ETL 数据库开发维护(oracle pl/sql) 2.自动化测试(javaseleniumcucumber) 2022年 功能测试 1.功能测试(学习测试用例,postman测试) 2.性能测试(jmeter初学) 2023年 测试开发 1.学习了…...
【Leetcode -86.分隔链表 -92.反转链表Ⅱ】
Leetcode Leetcode -86.分隔链表Leetcode -92.反转链表Ⅱ Leetcode -86.分隔链表 题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每…...
算法记录 | 48 动态规划
198.打家劫舍 思路: 1.确定dp数组(dp table)以及下标的含义:dp[i]:前 i 间房屋所能偷窃到的最高金额。 2.确定递推公式:dp[i] max(dp[i - 2] nums[i-1], dp[i - 1]) i间房屋的最后一个房子是nums[i−…...
CRM部署Always on 后 CRM报无法更新数据库,数据库只读,且读写分离不正常
CRM部署Always on 后 CRM报无法更新数据库,数据库只读,读写分离不正常 问题描述背景信息问题原因解决方案 问题描述 CRM部署Always on 后 CRM报无法更新数据库,数据库只读 读写分离不正常,出现错乱链接。 背景信息 1.2个节点配置SQL serve…...
麓言信息设计创意思维,打开设计师思路
在现在快速发展的时代,信息纷杂繁琐,如果一个设计不能让人眼前一亮,印象深刻,只会沦为平凡作品,无亮点无用处。正所谓,无设计不创意,这句口号正是喊出对设计的要求。 伴随着时代的发展、…...
POJ3704 括号匹配问题 递归方法
目录 题目 算法 完整代码 题目 参考 递归: https://blog.csdn.net/qq_45272251/article/details/103257953 利用了递归, 但思路稍复杂了 循环: https://blog.csdn.net/weixin_50340097/article/details/114579805 (看起来是递归其实是循环. 每次递归其实是循环内一次迭…...
leetcode — JavaScript专题(三):完全相等的 JSON 字符串、复合函数、 分组、柯里化、将对象转换为 JSON 字符串
专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷 2628. 完全相等的 JSON 字符串 题面 给定两个对象 o1 和 o2 ,请你检查它们是否 完全相等 。 对于两个 完全相等 的对象,它们必须包含相…...
OGNL 的表达式
目录 概念 基本原理 基本语法 1、访问Root区域对象基本语法 2、访问Context区域对象基本语法 符号含义 概念 Object-Graph Navigation Language 对象-图形导航语言, 主要用于访问对象的数据和方法。 基本原理 主要由3部分构成:1.OGNL引擎 …...
JAVA面试中遇到的那些坑,80%的人都种过招
面试,是很多学完Java开发的人不得不面对的问题。小编经常听到学员抱怨,明明觉得自己学的不错,为什么到了面试的时候就凉凉了?为什么有的面试官会一直问业务层面的问题,让人措手不及? 其实,我们在学习Java知识的同时…...
【测试开发】单元测试、基准测试和性能分析(以 Go testing 为例)
一、为什么需要测试🤔️ 你写不出 bug-free 的代码。你认为自己写出了 bug-free 的代码,但它在你意想不到的地方出错了。你觉得自己写出了永不出错的代码,但它的性能十分糟糕。 二、在开发过程中做好测试(理想情况下)…...
linux中一条命令查询当前端口的进程,然后拿到进程pid,作为另一条杀死进程的参数
1. 可以使用lsof命令来查询端口对应的进程,然后使用awk命令提取PID,最后将其作为另一条命令的参数。 例如,如果要查询端口为8080的进程: lsof -i :8080 | awk NR2{print $2}其中,-i选项指定查询网络连接,…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
