1. 装配(wiring)
创建应用对象之间协作关系的行为称为装配(wiring), 这也是依赖注入(DI)的本质.
2. spring装配机制:
1). 在XML中进行显式配置。
2). 在Java中进行显式配置。
public interface CompactDisc {
void play();
}
import org.springframework.stereotype.Component;
/*
* @Component注解。 这个简单的注解表明该类会作为组件类,
* 并告知Spring要为这个类创建bean。
*/
public class SgtPeppers implements CompactDisc{
@Override
public void play() {
System.out.println("config the beatles sing sgt. Pepper lonely hearts club band2");
}
}
public class CDPlayer{
private CompactDisc cd;
public CDPlayer(CompactDisc cd){
this.cd = cd;
}
public void play() {
cd.play();
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
* @Configuration注解表明这个类是一个配置类,
该类应该包含在Spring应用上下文中如何创建bean的细节。
*/
@Configuration
public class CDPlayerConfig {
/*
@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册
为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。
*/
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc cd){
return new CDPlayer(cd);
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) // 自动创建Spring的应用上下文
/*
@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。
因为CDPlayerConfig类中包含了@ComponentScan
*/
@ContextConfiguration(classes=CDPlayerConfig.class)
public class MyTest {
@Autowired
private CompactDisc cd;
@Autowired
private CDPlayer player;
@Test
public void test01(){
cd.play();
player.play();
}
}
3). 隐式的bean发现机制和自动装配。
spring从两个角度来实现自动化装配: 1). 组建扫描(component scanning): spring会自动发现应用上下文中所创建的bean。
2). 自动装配(autowiring):spring自动满足bean之间的依赖。
public interface CompactDisc {
void play();
}
import org.springframework.stereotype.Component;
/*
* @Component注解。 这个简单的注解表明该类会作为组件类,
* 并告知Spring要为这个类创建bean。
*/
@Component
public class SgtPeppers implements CompactDisc{
@Override
public void play() {
System.out.println("the beatles sing sgt. Pepper lonely hearts club band");
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/*
* 组件扫描默认是不启用的
* @ComponentScan注解启用了组件扫描
* @ComponentScan默认会扫描与配置类相同的包。Spring将会扫描这个包以及这个包下的所有子包, 查找带
有@Component注解的类。
*/
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) // 自动创建Spring的应用上下文
/*
@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。
因为CDPlayerConfig类中包含了@ComponentScan
*/
@ContextConfiguration(classes=CDPlayerConfig.class)
public class MyTest {
@Autowired
CompactDisc cd;
@Test
public void test01(){
cd.play();
}
}
当然如果你喜欢使用xml启动组件扫描,那么如下xml配置可以代替@ComponentScan
3. 在JavaConfig中引用xml配置
public interface CompactDisc {
void play();
}
import java.util.List;
public class BlankDisc implements CompactDisc{
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
super();
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
@Override
public void play() {
System.out.println("xml,javaconfig混合使用");
System.out.println("Playing "+title+" by"+artist);
for(String track : tracks){
System.out.println("-Track: "+track);
}
}
}
public class CDPlayer{
private CompactDisc cd;
public CDPlayer(CompactDisc cd){
this.cd = cd;
}
public void play() {
cd.play();
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
* @Configuration注解表明这个类是一个配置类,
该类应该包含在Spring应用上下文中如何创建bean的细节。
*/
@Configuration
public class CDPlayerConfig {
/*
@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册
为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。
*/
@Bean
public CDPlayer cdPlayer(CompactDisc cd){
return new CDPlayer(cd);
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:applicationContext.xml")
public class SoundSystemConfig {
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) // 自动创建Spring的应用上下文
/*
@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。
因为CDPlayerConfig类中包含了@ComponentScan
*/
@ContextConfiguration(classes=SoundSystemConfig.class)
public class MyTest {
//@Autowired
//private CompactDisc cd;
@Autowired
private CDPlayer player;
@Test
public void test01(){
player.play();
}
}
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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
<bean id="blankDisc" class="com.ag.test5.BlankDisc">
<constructor-arg value="sgt. Pepper"/>
<constructor-arg><value>the beatles</value></constructor-arg>
<constructor-arg>
<list>
<value>getting better</value>
<value>fixing a hole</value>
</list>
</constructor-arg>
</bean>
</beans>
4. 条件化的bean
Spring 4引入了一个新的@Conditional注解, 它可以用到带有@Bean注解的方法上。 如果给定的条件计算结果为true, 就会创建这个bean, 否则的话, 这个bean会被忽略。
5. 处理自动装配的歧义性
发生歧义性的时候, Spring提供了多种可选方案来解决这样的问题。 你可以将可选bean中的某一个设为首选(primary) 的
bean(使用@Primary注解), 或者使用限定符(qualifier) 来帮助Spring将可选的bean的范围缩小到只有一个bean。
Cake,Cookies都实现了Dessert接口,但是注入到Dessert类型时, 会将Cookies注入进去,避免了"org.springframework.beans.factory.NoUniqueBeanDefinitionException"
6. bean的作用域
7. 运行时值注入
如果希望避免硬编码值, 而是想让这些值在运行时再确定。如下,我们不希望把字符串写死。
为了实现这些功能, Spring提供了两种在运行时求值的方式:
1)。 属性占位符(Property placeholder) 。
占位符的形式为使用"${}"包装的属性名称。
为了使用占位符, 我们必须要配置一个PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bean。 从Spring3.1开始, 推荐使用PropertySourcesPlaceholderConfigurer, 因为它能够基于Spring Environment及其属性源来解析占位符。
2)。Spring表达式语言(SpEL Spring Expression Language)
SpEL拥有很多特性, 包括:
①使用bean的ID来引用bean;
②调用方法和访问对象的属性;
③对值进行算术、 关系和逻辑运算;
④正则表达式匹配;
⑤集合操作。
SpEL表达式要放到“#{ ... }”之中
SpEL可以表示字面值: 浮点数(#{3.14159}), String(#{'hello'})值以及Boolean(#{true})值。
SpEL还可以引用bean(#{sgtPeppers})、 属性(#{sgtPeppers.artist})和方法(#{artistSelector
.selectArtist()})
SpEL还可以使用T()在表达式中使用类型。
用来操作表达式值的SpEL运算符
运算符类型 | 运 算 符 |
算术运算 | +、 -、 * 、 /、 %、 ^ |
比较运算 | < 、 > 、 == 、 <= 、 >= 、 lt 、 gt 、 eq 、 le 、 ge |
逻辑运算 | and 、 or 、 not 、 │ |
条件运算 | ?: (ternary) 、 ?: (Elvis) |
正则表达式 | matches |
例如: #{2 * T(java.lang.Math).PI * circle.redius} // 使用了乘法运算符(*)
尽量让表达式简洁