Bean注入的方式有两种,一种是在XML中配置,此时分别有属性注入、构造函数注入和工厂方法注入;另一种则是使用注解的方式注入 @Autowired,@Resource,@Required。
2.1 在xml文件中配置依赖注入
2.1.1 属性注入
属性注入即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式。
属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。
package com.baobaotao.anno;
import org.springframework.beans.factory.BeanNameAware;
public class LogonService implements BeanNameAware{
private LogDao logDao;
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setLogDao(LogDao logDao) {
this.logDao = logDao;
}
public LogDao getLogDao() {
return logDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setBeanName(String beanName) {
System.out.println("beanName:"+beanName);
}
public void initMethod1(){
System.out.println("initMethod1");
}
public void initMethod2(){
System.out.println("initMethod2");
}
}
bean.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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName"
>
<bean id="logDao" class="com.baobaotao.anno.LogDao"/>
<bean id="userDao" class="com.baobaotao.anno.UserDao"/>
<bean class="com.baobaotao.anno.LogonService">
<property name="logDao" ref="logDao"></property>
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
2.1.2 构造方法注入
使用构造函数注入的前提是Bean必须提供带参数的构造函数。例如
package com.baobaotao.anno;
import org.springframework.beans.factory.BeanNameAware;
public class LogonService implements BeanNameAware{
public LogonService(){}
public LogonService(LogDao logDao, UserDao userDao) {
this.logDao = logDao;
this.userDao = userDao;
}
private LogDao logDao;
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setLogDao(LogDao logDao) {
this.logDao = logDao;
}
public LogDao getLogDao() {
return logDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setBeanName(String beanName) {
System.out.println("beanName:"+beanName);
}
public void initMethod1(){
System.out.println("initMethod1");
}
public void initMethod2(){
System.out.println("initMethod2");
}
}
bean.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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName">
<bean id="logDao" class="com.baobaotao.anno.LogDao"/>
<bean id="userDao" class="com.baobaotao.anno.UserDao"/>
<bean class="com.baobaotao.anno.LogonService">
<constructor-arg ref="logDao"></constructor-arg>
<constructor-arg ref="userDao"></constructor-arg>
</bean>
</beans>
2.1.3 工厂方法注入
非静态工厂方法:
有些工厂方法是非静态的,即必须实例化工厂类后才能调用工厂方法。
package com.baobaotao.ditype;
public class CarFactory {
public Car createHongQiCar(){
Car car = new Car();
car.setBrand("红旗CA72");
return car;
}
public static Car createCar(){
Car car = new Car();
return car;
}
}
工厂类负责创建一个或多个目标类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例,工厂类对外屏蔽了目标类的实例化步骤,调用者甚至不用知道具体的目标类是什么。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 工厂方法-->
<bean id="carFactory" class="com.baobaotao.ditype.CarFactory" />
<bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar">
</bean>
</beans>
静态工厂方法:
很多工厂类都是静态的,这意味着用户在无须创建工厂类实例的情况下就可以调用工厂类方法,因此,静态工厂方法比非静态工厂方法的调用更加方便。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="car6" class="com.baobaotao.ditype.CarFactory"
factory-method="createCar"></bean>
</beans>
2.2 使用注解的方式注入
2.2.1 使用@Autowired进行自动注入
Spring通过@Autowired注解实现Bean的依赖注入,下面是一个例子:
package com.baobaotao.anno;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
//① 定义一个Service的Bean(不需要在XML中定义Bean)
@Service
public class LogonService implements BeanNameAware{
//② 分别注入LogDao及UserDao的Bean(不需要在XML中定义property属性注入)
@Autowired(required=false)
private LogDao logDao;
@Autowired
@Qualifier("userDao")
private UserDao userDao;
public LogDao getLogDao() {
return logDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setBeanName(String beanName) {
System.out.println("beanName:"+beanName);
}
public void initMethod1(){
System.out.println("initMethod1");
}
public void initMethod2(){
System.out.println("initMethod2");
}
}
在①处,我们使用@Service将LogonService标注为一个Bean,在②处,通过@Autowired注入LogDao及UserDao的Bean。@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入到@Autowired标注的变量中。
2.2.2 使用@Autowired的required属性
如果容器中没有一个和标注变量类型匹配的Bean,Spring容器启动时将报NoSuchBeanDefinitionException的异常。如果希望Spring即使找不到匹配的Bean完成注入也不用抛出异常,那么可以使用@Autowired(required=false)进行标注:
@Service
public class LogonService implements BeanNameAware{
@Autowired(required=false)
private LogDao logDao;
...
}
默认情况下,@Autowired的required属性的值为true,即要求一定要找到匹配的Bean,否则将报异常。
2.2.3 使用@Qualifier指定注入Bean的名称
如果容器中有一个以上匹配的Bean时,则可以通过@Qualifier注解限定Bean的名称,如下所示:
@Service
public class LogonService implements BeanNameAware{
@Autowired(required=false)
private LogDao logDao;
//①注入名为UserDao,类型为UserDao的Bean
@Autowired
@Qualifier("userDao")
private UserDao userDao;
}
这里假设容器有两个类型为UserDao的Bean,一个名为userDao,另一个名为otherUserDao,则①处会注入名为userDao的Bean。
2.2.4 对类方法进行标注
@Autowired可以对类成员变量及方法的入参进行标注,下面我们在类的方法上使用@Autowired注解:
package com.baobaotao.anno;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class LogonService implements BeanNameAware{
private LogDao logDao;
private UserDao userDao;
@Autowired
public void setLogDao(LogDao logDao) {
this.logDao = logDao;
}
@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao) {
System.out.println("auto inject");
this.userDao = userDao;
}
}
如果一个方法拥有多个入参,在默认情况下,Spring自动选择匹配入参类型的Bean进行注入。Spring允许对方法入参标注@Qualifier以指定注入Bean的名称,如下所示:
@Autowired
public void init(@Qualifier("userDao")UserDao userDao,LogDao logDao){
System.out.println("multi param inject");
this.userDao = userDao;
this.logDao =logDao;
}
在以上例子中,UserDao的入参注入名为userDao的Bean,而LogDao的入参注入LogDao类型的Bean。
一般情况下,在Spring容器中大部分的Bean都是单实例的,所以我们一般都无须通过@Repository、@Service等注解的value属性为Bean指定名称,也无须使用@Qualifier按名称进行注入。