略
声明bean
构造器注入和Setter方法注入
装配bean
控制bean的创建和销毁
创建应用对象之间协作关系的行为通常称之为装配(wiring),这也是依赖注入(DI)的本质.
Spring配置的可选方案 Spring有三种主要的装配机制:
在XML中进行显示配置
在Java中进行显示配置
隐式的bean发现机制和自动装配
同时Spring的配置风格是可以互相搭配的,推荐使用自动配置,其次使用JavaConfig,最后是XML方式.
自动化装配bean Spring从两个角度来实现的自动化装配:
组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean.
自动装配(autowiring):Spring自动满足bean之间的依赖.
两者组合一起就可发挥强大的威力.
创建可被发现的bean CD接口
1 2 3 4 5 6 7 8 9 10 public interface CompactDisc { void play () ; } @Component public class SgtPeppers implements CompactDisc { private String msg = "sgtpepers" ; public void play () { System.out.println(msg); } }
默认组件扫描是不启动的,所以要手动启动它.
JavaConfig方式
默认扫描JavaConfig类同包下的类,也可以给 @ComponentScan(basePackages = "包路径")
参数来指定某个包.
1 2 3 4 5 @Configuration @ComponentScan public class CDPlayerConfig { }
XML方式
1 2 3 4 5 6 7 8 9 10 11 <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" 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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" > <context:component-scan base-package ="包路径" /> </beans >
测试
1 2 3 4 5 6 7 8 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CDPlayerConfig.class) public class MainTest { @Autowired private CompactDisc cd; @Test public void test () { System.out.println(cd); Assert.assertNotNull(cd); } }
为组件扫描的bean命名 当有多个CompactDisc需要被声明时,自动装载并不知道装载哪一个,所以需要给bean命名.
1 2 3 4 5 @Component("cd001") public class SgtPeppers implements CompactDisc { }
设置组件扫描的基础包 自动扫描注解 ComponentScan
有参数可以指定包,当扫描时它就仅仅在指定包内进行扫描.
1 2 @ComponentScan(basePackage="com.yuda.one") @ComponentScan(basePackage={"com.yuda.one","com.yuda.two"})
也可以指定类,注意:指定类后该类同包下的所有类(兄弟类)都可以被扫描到
1 2 @ComponentScan(basePackageClasses=CDPlayer.class) @ComponentScan(basePackageClasses={CDPlayer.class,DVDPlayer.class})
技巧: 使用basePackageClasses扫描可以扫描该类的兄弟类(同一包下的类),我们可以设置一个空标记接口,让JavaConfig能扫描到标记接口的兄弟类,好处自己想.
1 2 3 @Component public interface Marker {}
通过bean添加注解实现自动装配 现在组件已经有啦,就需要考虑把组件自动装配到哪一个对象上面去,这里用到了 @Autowired
标签,可以设置到构造器上,Setter方法上,字段上,甚至以组件为参数的任何方法上.
1 2 3 4 5 6 7 8 9 10 11 12 13 @Component public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired public CDPlayer (CompactDisc cd) { this .cd = cd; } @Override public void play () { System.out.println("CDPlayer开始播放" ); cd.play(); } }
还可以作用于Setter方法
1 2 3 4 @Autowired public void setCd (CompactDisc cd) { this .cd = cd; }
甚至可以作用于其他方法和字段
1 2 3 4 5 6 7 @Autowired private CompactDisc cd;@Autowired public void a (CompactDisc cd) { this .cd = cd; }
如果没有匹配的组件,Spring就会抛出一个异常,为了避免异常的出现可以给 @Autowired
添加required属性设置为false.那么及时没有匹配的组件,也不会报异常了,Spring会让这个bean处于为装配状态,配置该属性,很容易出现NullPointerException .
通过Java代码装配bean 尽管推荐使用自动装配的方式,但是有些情况是无法进行自动装配的,比如我想把第三方的组件添加到我的应用中,我总不能去更改别人写的代码,给它加上注解吧.所以啊通过Java代码来显式装配是极好的.与XML相比下,Java代码方式更为强大,类型安全并且对重构友好.但是JavaConfig是配置代码,它与其他的java代码不一样,它里面没有任何的业务逻辑.通常会把JavaConfig放到一个固定的包里面.
创建配置类 配置类需要@Configuration
来声明:这是一个配置类,然后使用@ComponentScan
来启动组件扫描,否则这个JavaConfig将无法获取任何组件.
1 2 3 4 5 @Configuration @ComponentScan(basePackageClasses = Marker.class) public class CDPlayerConfig { }
声明简单的bean 要在JavaConfig中显式声明Bean,我们需要编写一个方法,这个方法就代表了一个bean,格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Bean(name = "s1") public CompactDisc sgtPeppers () { return new SgtPeppers (); } @Bean(name = "s2") public CompactDisc randomBeatlesCD () { int choice = (int ) Math.floor(Math.random()*2 ); if (choice==0 ){ return new SgtPeppers2 (); } else { return new SgtPeppers (); } }
这里声明了两个组件
借助JavaConfig实现注入 上面是一个简单的bean,如果有一个复杂的bean,要如何装配呢?
第一种简单的方式是通过构造器来导入:
1 2 3 4 5 6 7 8 9 10 @Bean public CDPlayer cdPlayer () { return new CDPlayer (sgtPeppers()); } @Bean public CDPlayer annotherCdPlayer () { return new CDPlayer (sgtPeppers()); }
还有一种方式是这样的:
1 2 3 4 @Bean public CDPlayer cdPlayer (@Qualifier("s2") CompactDisc cd) { return new CDPlayer (cd); }
使用第二种方式更加灵活,比如可以这样:
1 2 3 4 5 6 7 @Bean public CDPlayer cdPlayer (@Qualifier("s2") CompactDisc cd) { CDPlayer cdPlayer = new CDPlayer (); cdPlayer.setCd(cd); return cdPlayer; }
通过XML装配bean 推荐使用JavaConfig但是对于老项目的维护,就需要学习XML方式装配bean.
创建XML配置规范 1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <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" > </beans >
声明一个简单 1 2 <bean id ="..." name ="..." class ="com.yuda.component.SgtPeppers" />
如果自己没给其命名,Spring会自动给其命名,为”类路径#计数”,如果有相同的类被声明为组件,那么根据后面的计数来分辨装配哪个.最好写上明确的id.name与id一样有一样功效,但是id任何情况不可相同,name有情况是可以相同的(但不建议).
XML中是不需要自行创建实例的,Spring发现这个时,他会调用默认构造器来创建bean.而在JavaConfig中,就必须使用new来创建实例.
注意:如果没有代码提示工具,class的错误可能会带来一些麻烦,所以class必须保证可以找到
借助构造器注入初始化bean 构造器注入有两种方式:
元素,写得多,但是灵活.
使用Spring3.0引入的c-命名空间,写得少,但是不灵活.
构造器注入bean引用 1 2 3 4 5 <bean id ="peppers" class ="com.yuda.component.SgtPeppers" /> <bean id ="cdplayer" class ="com.yuda.component.CDPlayer" > <constructor-arg ref ="peppers" /> </bean >
还可以使用c-标签,需要先声明c的命名空间
1 2 <bean id ="cdplayer" class ="com.yuda.component.CDPlayer" c:cd-ref ="peppers" /> <bean id ="cdplayer" class ="com.yuda.component.CDPlayer" c:_0-ref ="peppers" />
讲字面量注入到构造器中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class BlankDisc implements CompactDisc { private String title; private String artist; public BlankDisc (String title, String artist) { this .title = title; this .artist = artist; } public String getTitle () { return title; } public void setTitle (String title) { this .title = title; } public String getArtist () { return artist; } public void setArtist (String artist) { this .artist = artist; } @Override public void play () { System.out.println(title + "\t" + artist); } }
声明bean
1 2 3 4 <bean id ="blank" class ="com.yuda.component.BlankDisc" > <constructor-arg value ="title is aaa" /> <constructor-arg value ="a is bbb" /> </bean >
使用c
1 2 3 4 5 6 7 <bean id ="blank" class ="com.yuda.component.BlankDisc" c:title ="aaa" c:artist ="bbb" /> <bean id ="blank" class ="com.yuda.component.BlankDisc" c:_0 ="aaa" c:_1 ="bbb" />
装配集合 如果构造器需要注入一个集合.集合内为String类型数据
1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="blank" class ="com.yuda.component.BlankDisc" > <constructor-arg value ="title is aaa" /> <constructor-arg value ="a is bbb" /> <constructor-arg > <list > <value > 1</value > <value > 1</value > <value > 1</value > <value > 1</value > </list > </constructor-arg > </bean >
集合内为引用类型
1 2 3 4 5 <list > <ref bean ="peppers1" /> <ref bean ="peppers2" /> </list >
set同理,map如下:
1 2 3 <map > <entry key ="1" value ="1" /> </map >
设置属性 上述的是通过构造器来实现的注入,现在看看如何使用setter方法来实现.
1 2 3 <bean id ="cdplayer" class ="com.yuda.component.CDPlayer" > <property name ="cd" ref ="peppers" /> </bean >
其实也用来构造器,但是是无参的,类没有无参构造器会报错
通过属性注入还可以用p命名空间
1 2 3 4 5 6 7 8 9 <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:p ="http://www.springframework.org/schema/p" 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 ="cdplayer" class ="com.yuda.component.CDPlayer" p:cd-ref ="peppers" /> </beans >
根据Setter注入和使用构造器注入类似,但是标签无法做到集合的注入.这里需要用到另外一个命名空间—–util
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:c ="http://www.springframework.org/schema/c" xmlns:p ="http://www.springframework.org/schema/p" xmlns:util ="http://www.springframework.org/schema/util" 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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <util:list id ="my_list" > <value > 1</value > <value > 1</value > <value > 1</value > <value > 1</value > <value > 1</value > </util:list > <bean id ="blank" class ="com.yuda.component.BlankDisc" c:title ="aaa" c:artist ="bbb" c:tracks-ref ="my_list" > </bean > </beans >
通过id注入beans里面声明的list集合.
导入和混合配置 一个工程配置文件会非常多,所以需要导入
一个工程的不同业务使用JavaConfig或者XML,所以需要混合
在JavaConfig中引入XML配置 JavaConfig中导入JavaConfig
1 2 3 4 @Configuration @Import({CDPlayerConfig1.class,CDPlayerConfi2g.class,....}) public class MainConfig {}
JavaConfig中导入XML
1 2 3 4 @Configuration @ImportResource("classpath*:Spring.xml") public class MainConfig {}
在XML配置中引入JavaConfig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:c ="http://www.springframework.org/schema/c" xmlns:p ="http://www.springframework.org/schema/p" xmlns:util ="http://www.springframework.org/schema/util" 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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <bean class = "类路径" /> <import resource = "XXX.xml" /> </beans >
技巧: 可以有一个专门没有组件声明的XML,专门用来组装各种配置.