在应用中,我们常常使用<ref>标签为JavaBean注入它依赖的对象。但是对于一个大型的系统,这个操作将会耗费我们大量的资源,我们不得不花费大量的时间和精力用于创建和维护系统中的<ref>标签。实际上,这种方式也会在另一种形式上增加了应用程序的复杂性,那么如何解决这个问题呢?Spring为我们提供了一个自动装配的机制,尽管这种机制不是很完善,但是在应用中结合<ref>标签还是可以大大的减少我们的劳动强度。前面提到过,在定义Bean时,<bean>标签有一个autowire属性,我们可以通过指定它来让容器为受管JavaBean自动注入依赖对象。
<bean>的autowire属性有如下六个取值,他们的说明如下:
1、 No:即不启用自动装配。Autowire默认的值。
2、 byName:通过属性的名字的方式查找JavaBean依赖的对象并为其注入。比如说类Computer有个属性printer,指定其autowire属性为byName后,Spring IoC容器会在配置文件中查找id/name属性为printer的bean,然后使用Seter方法为其注入。
3、 byType:通过属性的类型查找JavaBean依赖的对象并为其注入。比如类Computer有个属性printer,类型为Printer,那么,指定其autowire属性为byType后,Spring IoC容器会查找Class属性为Printer的bean,使用Seter方法为其注入。
4、 constructor:通byType一样,也是通过类型查找依赖对象。与byType的区别在于它不是使用Seter方法注入,而是使用构造子注入。
5、 autodetect:在byType和constructor之间自动的选择注入方式。
6、 default:由上级标签<beans>的default-autowire属性确定。
注意:在配置bean时,<bean>标签中Autowire属性的优先级比其上级标签高,即是说,如果在上级标签中定义default-autowire属性为byName,而在<bean>中定义为byType时,Spring IoC容器会优先使用<bean>标签的配置。
下面通过一个综合示例来说明这一点
User.java
package com.javacrazyer.domain;
public class User {
private Long id;
private String username;
private String pwd;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
UserDao.java
package com.javacrazyer.dao;
import java.io.Serializable;
import com.javacrazyer.domain.User;
public interface UserDao {
void add(User user);
void delete(User user);
void update(User user);
User findById(Serializable id);
}
UserDaoHibernateImpl.java
package com.javacrazyer.dao;
import java.io.Serializable;
import com.javacrazyer.domain.User;
public class UserDaoHibernateImpl implements UserDao {
@Override
public void add(User user) {
System.out.println("UserDaoHibernateImpl:add方法");
}
@Override
public void delete(User user) {
System.out.println("UserDaoHibernateImpl:delete方法");
}
@Override
public User findById(Serializable id) {
System.out.println("UserDaoHibernateImpl:findById方法");
return null;
}
@Override
public void update(User user) {
System.out.println("UserDaoHibernateImpl:update方法");
}
}
UserDaoJDBCImpl.java
package com.javacrazyer.dao;
import java.io.Serializable;
import com.javacrazyer.domain.User;
public class UserDaoJDBCImpl implements UserDao {
@Override
public void add(User user) {
System.out.println("UserDaoJDBCImpl==add方法");
}
@Override
public void delete(User user) {
System.out.println("UserDaoJDBCImpl==delete方法");
}
@Override
public User findById(Serializable id) {
System.out.println("UserDaoJDBCImpl==findById方法");
return null;
}
@Override
public void update(User user) {
System.out.println("UserDaoJDBCImpl==update方法");
}
}
ServiceFacade.java
package com.javacrazyer.service;
import com.javacrazyer.dao.UserDao;
import com.javacrazyer.domain.User;
public class ServiceFacade {
//依赖的对象:主动去获取
private UserDao userDao;
public ServiceFacade(){}
//构造器
public ServiceFacade(UserDao userDao){
this.userDao = userDao;
System.out.println("调用带UserDao参数的构造方法");
}
//set方法
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void addUser(User user){
userDao.add(user);
}
public User findById(Long id){
return userDao.findById(id);
}
}
Spring配置applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- <bean id="userDao" class="com.javacrazyer.dao.UserDaoHibernateImpl"/>-->
<bean id="userDao" class="com.javacrazyer.dao.UserDaoJDBCImpl"/>
<!--自动装配 -->
<bean id="sf" class="com.javacrazyer.service.ServiceFacade" autowire="autodetect" />
<!-- <bean id="sf" class="com.javacrazyer.service.ServiceFacade" >-->
<!-- <property name="userDao" ref="userDao"/>-->
<!-- </bean>-->
</beans>
测试类
package com.javacrazyer.service.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.javacrazyer.domain.User;
import com.javacrazyer.service.ServiceFacade;
public class UserServiceTest {
@Test
public void testAddUser(){
//从Spring的Bean容器中获取想要的实例
//BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//ServiceFacade sf = (ServiceFacade)factory.getBean("sf");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
ServiceFacade sf = (ServiceFacade)context.getBean("sf");
sf.addUser(new User());
}
}
结果是
UserDaoJDBCImpl==add方法
如果将bean的id为UserDao的换成hibernate实现方式,那么结果就会是
UserDaoHibernateImpl==add方法
所以,在自动装配中无需像这样
<bean id="sf" class="com.javacrazyer.service.ServiceFacade" >
<property name="userDao" ref="userDao"/>
</bean>
配置引用注入对象
总结:
自动装配并不是十全十美的,我们不论是使用byName还是byType的方法,Spring不一定就能很准确的为我们找到JavaBean依赖的对象。另外,如果使用自动装配,Spring配置文件的可读性也大大降低,我们不能很容易的看出个bean之间的依赖关系,这也在一定程度上降低了程序可维护性。因此在使用自动装配时,应当权衡利弊,合理的与ref的方法相结合,尽量在降低工作量的同时,保证应用的可维护度。