Spring实战读书笔记Spring装配Bean
Posted xiueer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring实战读书笔记Spring装配Bean相关的知识,希望对你有一定的参考价值。
目录
Spring容器负责创建应用程序中的bean并通过DI来装配(wiring)他们。Spring有三种装配方式,三种方式可以搭配使用
(1)隐式的bean发现机制和自动装配(推荐使用)
(2)在java中显式装配
(3)在xml中显式装配
一、自动装配bean
Spring从2个角度实现自动装配
1、组件扫描:自动发现应用上下文中所创建的bean
2、自动装配:Spring自动满足bean之间的依赖
1、组件扫描
//例子,CD和CDPlayer
// CD接口
package soundsystem;
public interface CompactDisc
void play();
//实现类
package soundsystem;
import org.springframework.stereotype.Component;
@Component //组件注解
public class SgtPeppers implements CompactDisc
public void play()
System.out.println("play SgtPeppers");
在上面的例子中,SgtPeppers类上加了@Component注解,这个注解就表明该类是一个bean,Spring会自动识别到该bean并处理。Spring还支持使用@Named注解作为@Component的替代方案,使用较少。Spring会为每一个bean设定一个ID,默认情况下,未类型首字母小写,上例中bean id为sgtPeppers。如果需要显式的指定bean id,只需要将期望的ID值传递给@Component注解
@Component("longlyHeatsClub")// 指定bean id
public class SgtPeppers implements CompactDisc
...
不过组件扫描默认是不开启的,需要显式的配置开启组件扫描。Spring提供了2种配置方式:Java方式和xml方式。
java方式开启组件扫描
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan//开启组件扫描
public class CDPlayerConfigs
只需要新建一个配置类,并在该类上添加@ComponentScan注解变可以开启组件扫描。在例子中@ComponentScan没有加任何的参数,默认是扫描该配置类所在的包及其子包。如果要显式设定需要扫描的基础包,只需要在注解后面加上basePackages属性即可
@ComponentScan(basePackages="soundsystem")//指定基础包的报名
public class CDPlayerConfigs
@ComponentScan(basePackages="soundsystem","video")//指定多个基础包的报名
public class CDPlayerConfigs
以上的指定基础包的包名为字符串形式的,这种方式是类型不安全的,可能存在配置错误的情况。Spring还提供了一种方式,可以通过指定包中所包含的类或接口的方式配置。这些类所在的包将会被作为组件扫描的基础包。
@ComponentScan(basePackageClasses = CDPlayer.class, DVDPlayer.class)
public class CDPlayerConfigs
在实际使用中,可以考虑在包中单独创建一个用来进行扫描的空标记接口,将这些空标记接口配置在@ComponentScan中即可为需要的包开启组件扫描。
xml方式开启组件扫描
<?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:Context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<Context:component-scan base-package="soundsystem"/>
</beans>
以xml方式开启组件扫描需要要加入Context:component-scan元素即可。可以看到,xml方式开启组件扫描明显要比java方式复杂。
2、自动装配
自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。可以使用@Autowired开启自动装配。
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPalyer
private CompactDisc cd;
@Autowired //自动装配
public CDPlayer(CompactDisc cd)
this.cd = cd;
@Override
public void play()
cd.play();
@Autowired不仅可以用在构造方法上,还可以用在setter和其他任何方法上。在Spring初始化bean之后,他会尽可能的满足bean的依赖。如果找不到匹配bean,会抛出异常。可以设置required=false避免抛出异常。(谨慎使用)
@Autowired(required=false)
public CDPlayer(CompactDisc cd)
this.cd = cd;
@Autowired也可用用在变量上
二、通过Java代码装配Bean
大部分场景下都可以使用自动装配的方式实现自动化配置,但是在某些场景下还是需要显式的配置bean的,比如想要将第三方库中的组件装配到应用中,我们无法在别人的代码上添加@Component和Autowired注解。此时,就需要显式的配置了,Spring提供了2种显式配置的方式:Java和Xml。Java配置是比Xml更好的配置方式,他更强大,类型安全并且对重构友好。
现在,把前面例子中的@ComponentScan和@Component注解去掉。
...
public class SgtPeppers implements CompactDisc
public void play()
System.out.println("play SgtPeppers");
要如何获取到SgtPeppers bean呢?
1、简单配置
在JavaConfig中,写一个方法返回一个SgtPeppers,并添加@Bean注解就可以啦。@Bean注解会告诉Spring这个方法会返回一个对象,并且这个对象要注册为Spring应用上下文中的Bean。默认bean id与方法名是一样的,也可以指定bean id。
@Bean // 默认bean id为sgtPeppers
public CompactDisc sgtPeppers()
return new SgtPeppers();
@Bean(name = "lonelyHeartsClueBead")
public CompactDisc sgtPeppers()
return new SgtPeppers();
在这个方法中,可以加入自己的逻辑,这样实际上为bean创建赋予了极大的灵活性。只要最终返回的是一个CompactDisc即可。
2、依赖注入
以上是简单情况下的bean配置。如果要装配的bean又依赖于其他的bean呢?
@Bean
public CompactDisc sgtPeppers()
return new SgtPeppers();
@Bean
public CDPlayer cdPlayer()
return new CDPlayer(sgtPeppers());
这样就可以实现cdPlayer的bean装配了。只不过这里需要注意的是,看起来在创建cdPlayer实例的时候是是通过调用sgtPeppers()得到的,但是sgtPeppers()上是添加了@Bean注解的,所以实际上Spring会拦截所有对它的调用,并直接返回在Spring应用上下文中的那个bean(默认情况下,Spring的bean都是单例的)。所有无论有多少个方法调用sgtPeppers()的bean,其实都是用一个bean。
// 2个sgtPeppers()返回的bean是同一个
@Bean
public CDPlayer cdPlayer()
return new CDPlayer(sgtPeppers());
@Bean
public CDPlayer cdPlayer2()
return new CDPlayer(sgtPeppers());
当然,以上代码其实不是最好的依赖注入方式。下面的方式看起来更加的易于理解
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc)
return new CDPlayer(compactDisc);
cdPlayer 方法有一个参数,当Spring创建cdPlayer bean的时候,会自动为其装配一个CompactDisc。而且通过这种方式装配cdPlayer便不需要将compactDisc声明在同一个配置类中。他可以以任意的形式配置(Java/Xml),只要是一个Spring的bean即可。
三、通过Xml装配Bean
声明一个简单的bean
<bean class="soundsystem.SgtPeppers"/> <!-- 默认bean id为SgtPeppers#0,其中#0是序号 -->
<bean id="sgtPeppers" class="soundsystem.SgtPeppers"/> <!-- 指定bean id-->
借助构造器注入初始化bean
在xml中声明DI时,有多种可选的配置方案,具体到构造器注入,可以有2种基本的配置方案(1)<constructor-arg>方案(2)使用Spring3.0所引入的c-命名空间
public CDPlayer cdPlayer(CompactDisc compactDisc)
return new CDPlayer(compactDisc);
我们以上面的bean为例,假设需要创建这个bean,并且注入CompactDisc bean。可以使用如下方式注入bean引用。
方式1
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="sgtPeppers"/> //假设sgtPeppers已经在其他地方定义好了
</bean>
方式2
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="sgtPeppers"/>
除了可以注入bean的引用意外,还可以将字面量注入到构造器中。也可以将list/set集合注入到构造器中,而此集合中的元素又可以是字面量或者bean引用。
设置属性
假设存在如下的CDPlayer
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPalyer
private CompactDisc cd;
@Autowired
public void setCompactDisc(CompactDisc cd)
this.cd = cd;
@Override
public void play()
cd.play();
为了注入CDPlayer的cd属性,我们需要定义如下的bean
方法1 property属性注入
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="sgtPeppers"/>
</bean>
方法2 p命名空间注入
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="sgtPeppers"/>
同样的,除了为属性注入引用意外,还可以为其注入字面量(p命名空间不能注入集合)
混合配置
一般的项目规模较大是,不会只有一个配置文件,这时候可能就设计到配制之间的引用。
// Java中引用java
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfigs ...
// Java中引用xml
@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfigs ...
<!--xml中引用xml-->
<import resource="SpringConfig2.xml"/>
<!--xml中本身无法引用java配置,可以通过将java config定义为一个bean的方式间接引用这个java配置-->
<bean class="soundsystem.CDConfig"/>
当然是实际使用中,更常用的做法是定义一个更高层的配置文件(无论是java还是xml),其中引用所有的分模块的配置,以实现统一管理
以上是关于Spring实战读书笔记Spring装配Bean的主要内容,如果未能解决你的问题,请参考以下文章