在长生命周期的bean引用短生命周期bean时,会有一个问题。 比如singleton 类依赖了prototype类,容器会在singleton 类初始化时,就根据依赖关系将prototype类注入。以后的每一次调用singleton bean都是同一个对象,里面的prototype bean也是最初注入的那个,容器再也不会为singleton bean产生新的prototype bean。
在《作用域:使用代理aop:scoped-proxy》中我们通过在短生命周期的bean定义中加入<aop:scoped-proxy/>
就轻松解决了这个问题。
但是,有些业务情况要求在增加新的bean时,不允许改动以前的bean定义和旧的代码。简单的说:被调用者(短生命周期bean)不允许修改,只能修改调用者(新增的长生命周期bean),所以这篇就讲讲如何利用Lookup达到我们的要求。
Lookup方法的工作机制是使用cglib在产生字节码这个阶段生成一个代理类,因此我们先要在工程中引入cglib组件。
程序代码如下:
接口:
package twm.spring.lookup;
public interface UserSession {
Object getInstance();
}
接口的实现类:
package twm.spring.lookup;
public class UserSessionImpl implements UserSession{
@Override
public Object getInstance() {
return this;
}
}
业务类ServiceBean依赖UserSession:
因为setUserSession只是声明,并没有实现,所以是个抽象方法。声明这个抽象方法是为了让Lookup注入代理对象的。
当然也可以不声明为抽象方法(并不是强制要求),不过最终Lookup会覆盖原方法里的实现内容。
package twm.spring.lookup;
public abstract class ServiceBean {
UserSession userSession;
//原来的setter注入不要了
//public void setUserSession(UserSession userSession) {
// this.userSession = userSession;
//}
public Object Perform(){
this.userSession=setUserSession();
return this.userSession.getInstance();
}
//抽象方法,由lookup-method注入具体bean
abstract UserSession setUserSession();
}
beans.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:aop="http://www.springframework.org/schema/aop"
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-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<bean id="usession" class="twm.spring.lookup.UserSessionImpl" scope="prototype">
</bean>
<bean id="servicebean" class="twm.spring.lookup.ServiceBean">
<!-- <property name="UserSession" ref="usession"/> -->
<!-- name是类中返回代理对象的方法名,bean是lookup-method要代理的对象 -->
<lookup-method name="setUserSession" bean="usession"/>
</bean>
</beans>
调用代码:
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
ServiceBean us=ctx.getBean("servicebean",ServiceBean.class);
System.out.println(us.Perform());
System.out.println(us.Perform());
运行输出:
twm.spring.lookup.UserSessionImpl@13838e4
twm.spring.lookup.UserSessionImpl@1f34a6
打印出的两个usession对象的地址不一样,说明我们实现了每次调用都能获得新的短生命周期的对象。
<lookup-method>
标签中的name属性就是servicebean Bean中获取UserSession实例的方法,即:setUserSession()方法;bean属性是要注入的bean对象,这里是usession。