Spring装配Bean -- 《Spring In Action》

任何一个成功的App都是由多个为了实现某一个业务目标而相互协作的组件构成的。传统创建应用对象的方法是通过构造器或查找导致结构复杂难以复用测试的代码,基于Spring App中对象无需主动查找与自己相协作关联的对象,Spring容器会自动在目标组件需要时将相互协作对象的引用赋予各个对象。

Spring配置Bean常见三种方法

  • XML显式配置
  • 在Java中显式配置
  • 隐式的Bean发现机制和自动装配(优选)

自动化装配Bean

  • Spring从两个角度实现自动化装配
    • 组件扫描(Component Scanning): Spring会自动发现应用上下文中创建的bean;
    • 自动装配(autowiring):Spring自动满足Bean之间的依赖;
// CompactDisc接口在Java中定义CD的概念
// CompactDisc接口定义CD播放器对一盘CD所能进行的操作
interface CompactDisc{
void play();
}
// 带有@Component注解的CompactDisc实现类SgtPeppers
// @Component注解表明SgtPeppers会作为组件类
@Component
class SgtPeppers implements CompactDisc{
@Override
public void play() {
}
}
// @ComponentScan组件扫描会启动自动扫描所有带有@Component组件的bean
// 但是组件扫描默认关闭,开启的两种方法:1. @ComponentScan 2. 在Spring context中<context:component-scan>元素
@Configuration
@ComponentScan
class CDPlayerConfig{
}
// 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
class CDPlayerTest {
@Autowired
private CompactDisc compactDisc;
@Test
public void cdShouldNotNull(){
assertNotNull(compactDisc);
}
}

@ContextConfiguration会告诉需要在CDPlayerConfig中加载配置。CDPlayerConfig类中包含了@ComponentScan,最终应用上下文包含CompactDisc实现类的Bean,带有@Autowired注解将CompactDisc的Bean注入到测试代码之中

为组件扫描的bean命名 —— @Component("xxx")

默认情况下Spring应用上下文中所有bean都会有一个给定ID,eg: SgtPeppers bean设置ID,Spring会根据类名设置指定一个ID,SgtPeppers指定的ID是 sgtPeppers。这将类名的第一个字母变为小写。

  • 第一种方式定义别名
@Component("mySelfAlias)
public class SgtPeppers implements CompactDisc{
}
  • 第二种方式定义别名
@Named("mySelfAlias)
public class SgtPeppers implements CompactDisc{
}

设置组件基础扫描包 —— @ComponentScan("xxx.xxx.xxx")

一般默认组件扫描会扫描配置类所在包,如果需要扫描不懂的包需要指定扫描路径(basePackages属性更精确的确认扫描包的路径)

@Configuration
@ComponentScan(basePackage="xxx")
public class CDPlayerConfig{
}

如果需要设置多个扫描包 —— @ComponentScan(basePackage = {"xx","xx","xx",...})

@Configuration
@ComponentScan(basePackage={"xx","xx"})
public class CDPlayerConfig{
}

通过注解实现bean的自动装配

  • 第一种通过@Autowired(可以在构造器、Setter‘方法或其他普通方法上添加该注解进行装配bean)
@Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
// @Autowired用在构造器上实现bean自动装配
@Autowired
public CDPlayer(CompactDisc cd){
this.cd = cd;
}
public void play(){
cd.play():
}
// @Autowired用在setter方法上实现bean自动装配
@Autowired
public void setCompactDisc(compactDisc cd){
this.cd = cd;
}
// @Autowired用在普通方法上实现bean自动装配
@Autowired
public void insertDisc(CompactDisc cd){
this.cd = cd;
}
}

Spring通过@Autowired注解尝试满足方法参数上声明的依赖,如果没有匹配的bean则会抛出异常可以通过@Autowired(required=false)来屏蔽该异常

  • 第二种通过@Inject注解(源于Java依赖注入规范,在自动装配中Spring同时支持@Inject和@Autowired)

显示装配bean的两种途径(Java和XML)

第一种通过Java代码配置Bean

显示配置JavaConfig是很好的可选方案,JavaConfig强大、类型安全且对重构友好。在概念上,它与App中业务逻辑和领域代码不同,不包含任何业务逻辑,JavaConfig不会侵入任何业务逻辑代码之中。可以将其独立建包

  • 创建配置类&声明简单的Bean
// @Configuration注解表明此类是一个配置类,该类包含在Spring应用上下文中如何创建Bean的细节
@Configuration
public class CDPlayerConfig{
// @Bean 注解告诉Spring这个方法将返回一个对象,该对象要注册为Spring应用上下文中的bean。,如果需要更改该Bean的实例名称 -- @Bean(name="xxx")
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
// 在JavaConfig中装配Bean的简单方式是引用创建Bean的方法
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers());
}
// 一个小的业务逻辑实现: 自动从CD中选一张播放
@Bean
public CompactDisc randomBeatlesCD(){
int choice = (int)Math.floor(Math.random() * 4);
if(choice == 0){
return new SgtPeppers();
}else if(choice == 1){
return new WhiteAlbum();
}else if(choice == 2){
return new HardDaysNight();
}else{
return new Revolver();
}
}
}

第二种通过XML配置Bean

创建一个简单JavaBean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="soundsystem.SgtPeppers"/>
<bean id="compactDisc" class="soundsystem.SgtPeppers"/> <!--按照名字引用的bean减少繁琐-->
</beans>
<!-- 声明一个简单JavaBean,创建这个bean的类通过class属性来指定,对于相同类型的bean在没有id属性的前提下将默认采用”soundsystem.SgtPeppers#0" , "#0"是一个计数方式用来区分同类型的其他Bean。-->
构造器注入JavaBean
<bean id="compactDisc" class="ink.openmind.space01.SgtPeppers"/>
<!--
借助构造器注入初始化Bean
class CDPlayer implements MediaPlayer{
private CompactDisc compactDisc;
public CDPlayer(CompactDisc compactDisc){
this.compactDisc = compactDisc;
}
}
-->
<bean id="cdPlayer" class="ink.openmind.space01.CDPlayer">
<constructor-arg ref="compactDisc"/> <!-- c:compactDisc-ref="compactDisc" ; 使用【c:】命名空间来替换<constructor-arg>-->
</bean>
将字面量注入构造器中
<!--
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
public BlankDisc(String title, String artist){
this.title = title;
this.artist = artist;
}
}
-->
<bean id="compactBlankDisc" class="ink.openmind.space01.BlankDisc">
<constructor-arg value="Test"/>
<constructor-arg value="The Beatles"/>
<!-- 使用c:命名空间替代
c:_title="Test"
c:_artist="The Beatles"
-->
</bean>
装配集合

无论那种集合类型都可以使用来传递

  • 构造参数类型:java.util.list
<!-- 传入List<String>-->
<bean id="xxx" class="xxx.xxx">
<constructor-arg>
<list>
<value>xxxxxxxx</value>
<value>xxxxxxxx</value>
....
</list>
</constructor-arg>
</bean>
<!-- 传入List<Bean> -->
<bean id="xxx" class="xxx.xxx">
<constructor-arg>
<list>
<ref bean="xxx“/>
<ref bean="xxx"/>
....
</list>
</constructor-arg>
</bean>
  • 构造参数类型:java.util.set
<bean id="xxx" class="xxx.xxx">
<constructor-arg>
<set>
<!-- 传入字面量-->
<value>xxx</value>
<value>xxx</value>
<value>xxx</value>
....
<!-- 传入Bean-->
<ref bean="xxx“/>
<ref bean="xxx"/>
....
</set>
</constructor-arg>
</bean>
posted @   Felix_Openmind  阅读(216)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示