lookup method注入是spring动态改变bean里方法的实现。方法执行返回的对象,使用spring内原有的这类对象替换,通过改变方法返回值来动态改变方法。内部实现为使用cglib方法,重新生成子类,重写配置的方法和返回对象,达到动态改变的效果。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--lookup-method动态注入-->
<bean id="myCommand" class="com.picc.spring.lookupmethod.SynCommand" scope="prototype"></bean>
<bean id="commandManager" class="com.picc.spring.lookupmethod.CommandManager">
<lookup-method name="crateCommand" bean="myCommand"></lookup-method>
</bean>
</beans>
package com.picc.spring.lookupmethod;
public class Command{
private Object commcandState;
public Command() {
System.out.println("i am command");
}
public void setCommcandState(Object commcandState) {
this.commcandState = commcandState;
}
public Object execute() {
return "hello look-up method";
}
}
package com.picc.spring.lookupmethod;
public class AsyncCommand extends Command{
public AsyncCommand() {
System.out.println("i am async");
}
public Object execute() {
return "hello look-up method AsyncCommand";
}
}
package com.picc.spring.lookupmethod;
public class SynCommand extends Command{
public SynCommand() {
System.out.println("i am sync");
}
public Object execute() {
return "hello look-up method SynCommand";
}
}
package com.picc.spring.lookupmethod;
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = crateCommand();
System.out.println(command);
command.setCommcandState(commandState);
return command.execute();
}
protected abstract Command crateCommand();
}
@Test
public void testlookupMethod(){
CommandManager clientService = classPath.getBean("commandManager", CommandManager.class);
clientService.process(1);
// clientService = classPath.getBean("commandManager", CommandManager.class);
clientService.process(1);
System.out.println(clientService);
}
其中,最为核心的部分就是lookup-method的配置。上面代码中,我们可以看到crateCommand()方法是个抽象方法,我们并没有实现它啊,那它是怎么调用的呢。这里的奥妙就是Srping应用了CGLIB(动态代理)类库。Spring在初始化容器的时候对配置的bean做了特殊处理,Spring会对bean指定的class做动态代理,代理标签中name属性所指定的方法,返回bean属性指定的bean实例对象。每次我们调用CommandManager 这个bean的crateCommand()方法时,其实是调用了CGLIB生成的动态代理类的方法。
<bean id="commandManager" class="com.picc.spring.lookupmethod.CommandManager">
<lookup-method name="crateCommand" bean="myCommand"></lookup-method>
</bean>
method是commandManager中的一个方法,commandManager和crateCommand是不是抽象都无所谓,不会影响CGLIB的动态代理,根据项目实际需求去定义。non-singleton-bean指的是lookup-method中bean属性指向的必须是一个非单例模式的bean,当然如果不是也不会报错,只是每次得到的都是相同引用的bean(同一个实例),这样用lookup-method就没有意义了。