§1 什么是自动装配?
§2 自动装配的意义?
§3 自动装配有几种类型?
§4 如何启用自动装配?
§5 自动装配将引发的问题?
§1 什么是自动装配?
Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。
简而言之,就是对于bean当中引用的其他bean不需要我们自己去配置它改使用哪个类,Spring 的自动装配可以帮助我们完成这些工作。
§2 自动装配的意义?
引用
理解自动装配的优缺点是很重要的。其中优点包括:
自动装配能显著减少配置的数量。不过,采用bean模板(见这里)也可以达到同样的目的。
自动装配可以使配置与java代码同步更新。例如,如果你需要给一个java类增加一个依赖,那么该依赖将被自动实现而不需要修改配置。因此强烈推荐在开发过程中采用自动装配,而在系统趋于稳定的时候改为显式装配的方式。
§3 自动装配有几种类型?
Spring reference 写道
5种模式 说明
no 默认不使用autowiring。 必须显示的使用"<ref />"标签明确地指定bean合作者,对于部署给予更大的
控制和明了。
byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自
动装配。例如,在bean定义中将 autowire设置为by name,而该bean包含master属性(同时提供
setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的
bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,
则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置
dependency-check="objects"让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类
型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。
如果发现默认的构造器,那么将使用byType方式。
§4 如何启用自动装配?
你可以参照以下的配置去启用自动装配
引用
<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"
default-autowire="byType" >
当然,这里的byType你可以更改为其他你想要的装配类型。
§5 自动装配将引发的问题?
自动装配的一些缺点:
尽管自动装配比显式装配更神奇,但是,正如上面所提到的,Spring会尽量避免在装配不明确的时候进行猜测,因为装配不明确可能出现难以预料的结果,而且Spring所管理的对象之间的关联关系也不再能清晰的进行文档化。
对于那些根据Spring配置文件生成文档的工具来说,自动装配将会使这些工具没法生成依赖信息。
自动装配可以减轻配置的工作量,但同时使得配置文件的可读性变得很差,因为你不可能从配置文件
中获知这些对象之间得依赖关系,从而维护困难!
注意:
当根据类型进行自动装配的时候,容器中可能存在多个bean定义跟自动装配的setter方法和构造器参数类型匹配。这样就会存在模棱两可的问题。如果bean定义不唯一,装配时就会抛出异常。
解决方案(任选其一):
1 放弃使用自动装配,使用显示装配。
2 将bean排除在自动装配之外,
引用
两个功能:
1 通过设定bean定义中的'autowire-candidate'属性显式的设置为'true' 或 'false'来设置其是否为被自动装配
对象。
2 使用对bean名字进行模式匹配来对自动装配进行限制,其做法是在<beans/>元素的
'default-autowire-candidates' 属性中进行设置。可以使用通配符,如以'Repository'结尾的bean,
那么可以设置为"*Repository“。
3 通过在bean定义中设置'primary'属性为'true'来将该bean设置为首选自动装配bean。
如何使用Spring autowire请取决于你的项目设计。
进一步理解自动装配:
Spring的自动装配(byName;byType) 好处:大幅度减少Spring配置
坏处:依赖不能明确管理,可能会有多个bean同时符合注入规则。没有清晰的依赖关系。public class UserDAOImpl implements UserDAO { private int daoId; public int getDaoId() { return daoId; } public void setDaoId(int daoId) { this.daoId = daoId; } public void save(User user) { System.out.println("user saved!"); } @Override public String toString() { return "daoId=" + daoId; } } UserService 依赖了UserDAO public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }
<?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-2.5.xsd" > <bean name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl"> <property name="daoId" value="1"></property> </bean> <bean name="userDAO2" class="com.bjsxt.dao.impl.UserDAOImpl"> <property name="daoId" value="2"></property> </bean> <bean id="userService" class="com.bjsxt.service.UserService" autowire="byName">
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); System.out.println(service.getUserDAO());
改成byType的话 是按照类型自动装配 如果按照上面的写法 就把autowire="byType"> 那么将会报错 因为你的UserDAO 和UserDAO1的类型是一样的 都是class="com.bjsxt.dao.impl.UserDAOImpl" 的
下面通过完整的例子,来说明自动装配:
public interface UserDAO { public void save(User user); }
public class UserDAOImpl implements UserDAO { public void save(User user) { System.out.println("user saved!"); } }
public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
public class UserService { private UserDAO userDAO; public void init() { System.out.println("init"); } public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } <strong>@Autowired</strong> public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public void destroy() { System.out.println("destroy"); } }
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <strong><context:annotation-config /></strong> <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
<bean id="userService" class="com.bjsxt.service.UserService" > </bean> </beans>
假如说有两个相同的bean,配置文件如下:
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> <strong> <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"> </bean> <bean id="u2" class="com.bjsxt.dao.impl.UserDAOImpl"></bean> <bean id="userService" class="com.bjsxt.service.UserService" ></strong> </bean> </beans>
<strong>class="com.bjsxt.dao.impl.UserDAOImpl"></strong>怎么解决呢?
这样装配一下就行了:
@Autowired public void setUserDAO<strong>(@Qualifier("u")</strong> UserDAO userDAO) { this.userDAO = userDAO; }用到了:@Qualifier,指定<bean>的名字就行了。
同样还是上面的问题,还一种解决方法就是用:@Resource //就是资源的意思
@Resource(name="userDAO") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; }
下面介绍:@Component("u") ,实现配置文件零配置 @Repository @Service @Controller @Component这四个注解在很多版本中的作用一模一样的,还没有区分出来
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <strong><context:annotation-config /> <context:component-scan base-package="com.bjsxt"/> //配置后,Spring自动扫描package为com.bjsxt下的所有文件</strong> </beans>
<strong>@Component("u") //相当于@Component(value="u")</strong> public class UserDAOImpl implements UserDAO { public void save(User user) { System.out.println("user saved!"); } }
<strong>@Component("userService") //相当于@Component(value="userService")</strong> public class UserService { private UserDAO userDAO; public void init() { System.out.println("init"); } public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } <strong>@Resource(name="u")</strong> public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } public void destroy() { System.out.println("destroy"); } }
测试代码:
public class UserServiceTest { @Test public void testAdd() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); service.add(new User()); ctx.destroy(); } }
再看一个常用的注解:@Component("userService")构造完成之后执行, @PreDestroy对象销毁之前执行
@Component("userService") public class UserService { private UserDAO userDAO; @PostConstruct public void init() { System.out.println("init"); } public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } @Resource(name="u") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } @PreDestroy public void destroy() { System.out.println("destroy"); } }
最后小结:
7.自动装配 a)Spring_0800_IOC_AutoWire b)byName c)byType d)如果所有的bean都用同一种,可以使用beans的属性:default-autowire 8.生命周期 a)Spring_0900_IOC_Life_Cycle b)lazy-init (不重要) c)init-method destroy-methd 不要和prototype一起用(了解) 9.Annotation第一步: a)修改xml文件,参考文档<context:annotation-config /> 10.@Autowired a)默认按类型by type b)如果想用byName,使用@Qulifier c)写在private field(第三种注入形式)(不建议,破坏封装) d)如果写在set上,@qualifier需要写在参数上 11.@Resource(重要) a)加入:j2ee/common-annotations.jar b)默认按名称,名称找不到,按类型 c)可以指定特定名称 d)推荐使用 e)不足:如果没有源码,就无法运用annotation,只能使用xml 12.@Component @Service @Controller @Repository a)初始化的名字默认为类名首字母小写 b)可以指定初始化bean的名字 13.@Scope 14.@PostConstruct = init-method; @PreDestroy = destroy-method;