Setter注入
之前的用XML配置Bean的实例中已经有通过setter注入的方式,通过在XML文件中使用 < property name=“”, ref=“”>标签,name特性表示依赖属性的名称,ref表示注入其中的Bean的名称
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
</bean>
除此之外,还可以用<property>标签的value特性直接为Bean内属性赋值
<bean id="account1" class="com.wiley.beginningspring.ch2.Account">
<property name="id" value="1" />
<property name="ownerName" value="John" />
<property name="balance" value="10.0"/>
<property name="locked" value="false" />
</bean>
<bean id="account2" class="com.wiley.beginningspring.ch2.Account">
<property name="id" value="2" />
<property name="ownerName" value="Mary" />
<property name="balance" value="20.0"/>
<property name="locked" value="false" />
</bean>
如果需要注入的是Collection或者Map属性,也可以用<map>、<set>等标签为之赋值
<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl">
<property name="accountsMap">
<map>
<entry key="1" value-ref="account1"/>
<entry key="2" value-ref="account2"/>
</map>
</property>
</bean>
构造函数注入
此时在Bean的定义中加入<constructor>标签采用其含参构造函数即可
首先给AccountServiceImpl定义一个含参构造函数
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
然后在XML配置文件中采用<constructor>标签
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
<constructor-arg ref="accountDao"/>
</bean>
此处ref属性同样是指向需要注入的Bean
当然,和<property>标签一样,<constructor>标签也可以用value属性来接收值,此外,当以一个类有多个构造函数时,还可通过index属性来指定参数在构造函数的位置从而指定构造函数
考察如下Foo类以及与之相关的Bar类和Baz类
public class Foo {
private Bar bar;
private Baz baz;
public Foo(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
public Foo(Baz baz, Bar bar) {
this.bar = bar;
this.baz = baz;
}
}
public class Bar {
}
public class Baz {
}
此时的Bean配置需要指定两个参数序号确定使用的构造函数
<bean id="foo" class="com.wiley.beginningspring.ch2.Foo">
<constructor-arg ref="bar" index="0"/>
<constructor-arg ref="baz" index="1"/>
</bean>
<bean id="bar" class="com.wiley.beginningspring.ch2.Bar"/>
<bean id="baz" class="com.wiley.beginningspring.ch2.Baz"/>
bar序号为0,baz序号为1,采用构造函数
public Foo(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
注意序号从0开始
构造函数+Setter注入
给类定义一个构造函数和Setter
public class Foo {
private Bar bar;
private Baz baz;
public Foo(Bar bar) {
this.bar = bar;
}
public void setBaz(Baz baz) {
this.baz = baz;
}
}
此时可以在同一个Bean标签下完成构造函数和setter的注入
<bean id="foo2" class="com.wiley.beginningspring.ch2.Foo">
<constructor-arg ref="bar"/>
<property name="baz" ref="baz"/>
</bean>
Bean定义重写
当不同的配置源中存在两个同名的Bean定义的时候,根据给定顺序的第二个Bean定义将会重写第一个Bean定义。相同的配置源中不允许出现两个同名Bean定义。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
Configuration1.class, Configuration2.class);
在容器创建中如此组合了这样两个配置类时,重复的Bean会按照Configuration2.class中的配置
depends-on特性
该特性存在于<bean>标签内,用于指定bean之间的依赖关系,这样的依赖关系决定他们的创建和销毁顺序
<bean id="a" class="com.wiley.beginningspring.ch2.A" depends-on="b,c"/>
这样创建的Bean a依赖于Bean b和c,a会在b, c创建之后被创建,且如果a不是无状态Bean会在b, c销毁前销毁
无状态Bean和有状态Bean
无状态Bean没有状态变量。
例如
public class A { public A() {} public String hello() { return "Hello 谁?"; } }
相比之下有状态Bean存在状态变量,例如
public class B { private String name; public B(String arg) { this.name = arg; } public String hello() { return "Hello" + this.name; } }
其中的name就是状态变量
详情参见 有状态Bean和无状态Bean
自动装配
可以不在Bean定义中显式定义依赖项而是让Spring容器自动往Bean中注入依赖项,有byType、byName和constructor三种模式
byType模式
byType模式中Spring通过反射查看Bean中定义的类,然后注入容器中类型匹配的属性,通过调用这些属性的setter方法完成
- XML配置
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl" autowire="byType"/>
<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl"/>
- Java配置
@Bean(autowire=Autowire.BY_TYPE)
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
return bean;
}
容易发现,有多个类型Bean可以装配的时候会装配失败
byName模式
- XML配置
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl" autowire="byName"/>
<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl"/>
- Java配置
@Bean(autowire=Autowire.BY_TYPE)
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
return bean;
}
@Autowired
使用该注解时不必向@Bean注解添加autowire特性也可实现自动装配,加了@Autowired注解的setter方法会自动注入合适依赖
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Autowired
@Qualifier
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//Implementation
}
@Configuration
public class Ch2BeanConfiguration {
@Bean
@Qualifier
public AccountDao accountDao() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
}
该种方法在有多个符合条件依赖项时应该添加@Qualifier注解指定注入的Bean,此时装配模式变为byName
Bean查找
在Spring容器控制之外的地方获取Bean可用ApplicationContext.getBean()方法执行显式Bean查找