依赖关系注入之后的行为:
Spring提供两种方式在Bean的全部属性设置成功后执行特定的行为:
- 使用init-method属性。
- 实现InitializingBean接口。
第一种方式:使用init-method属性指定某个方法在Bean全部依赖关系设置结束后自动执行。使用这种方式不需要讲代码与Spring的接口耦合在一起,代码污染小。
第二种方式:让Bean类实现initlializingBean接口,该接口提供一个方法void afterPropertiesSet() thorows Exception;Spring会在为该Bean注入依赖关系之后,调用该Bean所实现的afterPropertiesSet()方法。
Chinese.java
package entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import inter.Axe;
import inter.Persion;
public class Chinese implements Persion,InitializingBean,BeanNameAware,ApplicationContextAware {
private Axe axe;
@Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
System.out.println("======setApplicationContext=======");
}
public Chinese()
{
System.out.println("Spring实例化主调Bean:Chinese实例...");
}
@Override
public void setBeanName(String arg0) {
// TODO Auto-generated method stub
System.out.println("=============setBeanName===============");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("正在执行初始化方法afterPropertiesSet.....");
}
@Override
public void useAxe() {
// TODO Auto-generated method stub
System.out.println(axe.chop());
}
public void setAxe(Axe axe)
{
System.out.println("Spring调用setAxe()执行依赖注入...");
this.axe=axe;
}
public void init()
{
System.out.println("正在执行初始化方法init....");
}
}
beans.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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<bean id="steelAxe" class="entity.SteelAxe"/>
<!-- 配置ChineseBean,使用init-method="init" -->
<bean id="chinese" class="entity.Chinese" init-method="init">
<property name="axe" ref="steelAxe" />
</bean>
</beans>
输出
Spring实例化主调Bean:Chinese实例...
Spring调用setAxe()执行依赖注入...
=============setBeanName===============
======setApplicationContext=======
正在执行初始化方法afterPropertiesSet.....
正在执行初始化方法init....
钢斧砍柴真快!
如果某个类实现了Initializing接口,当该Bean所有的依赖关系被设置完成后,Spring容器会自动调用该Bean实例的setPropertiesSet()方法;其执行结果与采用init-method属性指定生命周期一样。但现实Initializing接口污染代码,是低侵入式设计。
Bean销毁之前的行为:
Spring提供了两种定制Bean实例销毁之前的特定行为:
- 使用destroy-method属性。
- 实现DisposableBean接口。
第一种方式:使用destroy-method属性指定某个方法在Bean销毁之前自动被执行,使用这种方式不需将代码与Spring的接口耦合在一起,代码污染低。
第二种方式:让Bean类实现DisposableBean接口,实现该接口提供的方法void destroy() throws Exception。
配置文件与实例化之后的beans.xml文件类似。
协调作用域不同步的Bean:
当singleton作用域的Bean依赖于prototype作用域的Bean时,会产生不同步的现象,解决该问题有两种思路:
- 放弃依赖注入:singleton作用域的Bean每次需要prototype作用域的Bean时,主动向容器请求新的Bean实例,即可保证每次注入的prototype Bean实例都是最新的实例。
- 利用方法注入:方法注入通常采用lookup方法注入。
为了使用lookup方法注入,大致需要两步
- 将调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean。
- 在<bean.../>元素中添加<lookup-method.../>子元素让Spring为调用者Bean的实现类实现指定的抽象方法。
Chinese.java
public abstract class Chinese implements Persion
{
private Dog dog;
//定义抽象方法,该方法用于获取被依赖的Bean
public abstract Dog getDog();
public void hunt()
{
System.out.println("我带着"+getDog()+"出去打猎");
System.out.println(getDog().run());
}
}
使用<lookup-method.../>元素需要指定如下两个属性:
- name:指定需要让Spring实现的方法。
- bean:指定Spring实现该方法的返回值。
beans.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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<bean id="chinese" class="entity.Chinese">
<!-- Spring只要检测到lookup-method元素,Spring会自动为该元素的name属性所指定的方法提供实现体 -->
<lookup-method name="getDog" bean="gunDog"/>
</bean>
<!-- 指定gunDog Bean的作用域为prototype,希望程序每次使用该Bean时都得到不同的实例 -->
<bean id="gunDog" class="entity.GunDog" scope="prototype">
<property name="name" value="旺财"/>
</bean>
</beans>
Spring会采用运行时动态增强的方式来实现<lookup-method.../>元素所指定的抽象方法,如果目标抽象类(如上Chinese类)实现过接口,Spring会采用JDK动态代理来实现该抽象类,并为之实现抽象方法;如果抽象类没有实现过接口,Spring会采用cglib实现该抽象类,并为之实现抽象方法。