Lookup方法注射指容器能够重写容器中bean的抽象或具体方法,返回查找容器中其他bean的结果。 被查找的bean在上面描述的场景中通常是一个non-singleton bean (尽管也可以是一个singleton的)。Spring通过使用CGLIB库在客户端的类之上修改二进制码, 从而实现上述的场景要求。
包含方法注入的客户端类,必须按下面的形式的抽象(具体)定义方法:
protected abstract SingleShotHelper createSingleShotHelper();
如果方法不是抽象的,Spring就会直接重写已有的实现。在XmlBeanFactory的情况下,你可以使用bean定义中的lookup-method 属性来指示Spring去注入/重写这个方法,以便从容器返回一个特定的bean。举个例子说明:
<!-- a stateful bean deployed as a protype (non-singleton) -->
<bean id="singleShotHelper class="..." singleton="false">
</bean>
<!-- myBean uses singleShotHelper -->
<bean id="myBean" class="...">
<lookup-method name="createSingleShotHelper"
bean="singleShotHelper"/>
<property>
...
</property>
</bean>
当myBean需要一个新的singleShotHelper的实例的时候, 它就会调用它自己的createSingleShotHelper 方法。 值得注意的是:部署beans的人员必须小心地将singleShotHelper作为一个non-singleton部署 (如果确实需要这么做)。如果它作为一个singleton(除非明确说明,否则缺省就是singletion)而部署, 同一个singleShotHelper实例将会每次被返回。
注意Lookup方法注射能够同构造函数注射结合(对创建的bean提供可选的构造函数参数), 也可以同setter方法注射结合(在创建的bean之上设置属性)。
public class UserDao {
public UserDao(){}
private String name = "";
public UserDao(String name) {
this.name = name;
}
public void create() {
System.out.println("create user from - " + name);
}
}
public abstract class UserManager {
public UserDao getUserDao() {
return new UserDao("UserManager.getUserDao()");
}
public void createUserDao() {
UserDao dao = getUserDao();
dao.create();
}
//方法注入所需要的方法,由spring提供实现
public abstract UserDao getSingleUserDao();
}
<bean name="userManager" class="com.yoyousfot.spring.lookup.UserManager">
<lookup-method name="getSingleUserDao" bean="userDao"/>
</bean>
<bean name="userDao" class="com.yoyousfot.spring.lookup.UserDao">
<constructor-arg>
<value>lookup method</value>
</constructor-arg>
</bean>
通过这种机制我们可以在不修改原系统代码的情况下,可以轻易的把UserDao换成别的类型相容的对象而不会影响原系统。Spring是使用CGLIB在字节码级别动态实现出userManager的子类,并重写getUserDao方法的方式来实现这个神奇的功能的。