无状态Bean的作用域一般可以配置为singleton,如果我们往singleton的Pilot类中注入prototype的Plane类,并希望每次调用Pilot的getPlane()方法都能返回一个新的planeBean,该怎么办呢?
如果我们使用传统的注入方式将无法实现这样的需求,因为Singleton的Bean注入关联Bean的动作仅有一次,虽然planeBean的作用范围是prototype,但是Pilot通过getPlane()方法返回的对象还是最开始注入的那个planeBea
如果希望每次每次调用getPlane()方法都返回一个新的planeBean,一种可选的方法是让Pilot类实现BeanFactoryAware接口,且能够访问容器的引用。
但是上面的方法依赖SPring框架接口,十分不友好。有没有其他办法呢?
通过方法注入的方案完美的解决这个问题。
lookup方法注入
SpringIoC容器拥有复写Bean方法的能力,主要源于CGLib类包。CGlib可以找运行期间动态操作class字节码,为Bean动态创建子类或者实现类。
package com.xgj.ioc.lookup;
public class Plane {
public void fly() {
System.out.println('ready to fly');
}
}
方法一通过在配置文件中配置的方式实现
我们声明一个MagicPilot接口,并声明一个getPlane接口方法
下面不编写任何实现类,仅通过配置为该接口提供动态的实现,让getPlane接口方法每次都返回新的planeBean。
<量化接口,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.xsd'>
<量化接口,bean id='plane' class='com.xgj.ioc.lookup.Plane' scope='prototype' />
<量化接口,bean id='magicPilot' class='com.xgj.ioc.lookup.MagicPilot'>
量化接口,bean>
量化接口,beans>
通过lookup-method元素标签为MagicPlane的getPlane方法提供动态实现,返回prototype类型的Plane量化接口,bean,这样Spring将在运行期为MagicPlane接口提供动态实现。等同于方式
测试类
package com.xgj.ioc.lookup;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LookupTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
'classpath:com/xgj/ioc/lookup/量化接口,beans.xml');
Plane plane = ctx.getBean('magicPilot', MagicPilot.class).getPlane();
plane.fly();
System.out.println(ctx.isPrototype('plane'));
}
}
测试结果:
方法二通过实现接口代码的方式实现
编写MagicPilot的实现类,实现MagicPilot和ApplicationContextAware接口
package com.xgj.ioc.lookup;
import org.springframework.量化接口,beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class MagicPilotImpl implements MagicPilot, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Plane getPlane() {
return (Plane) applicationContext.getBean('plane');
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
修改配置文件
<量化接口,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.xsd'>
<量化接口,bean id='plane' class='com.xgj.ioc.lookup.Plane' scope='prototype' />
<量化接口,bean id='magicPilotImpl' class='com.xgj.ioc.lookup.MagicPilotImpl'/>
量化接口,beans>
修改测试类
package com.xgj.ioc.lookup;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LookupTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
'classpath:com/xgj/ioc/lookup/量化接口,beans.xml');
MagicPilotImpl magicPilotImpl = ctx.getBean('magicPilotImpl',
MagicPilotImpl.class);
magicPilotImpl.getPlane().fly();
System.out.println(ctx.isPrototype('plane'));
}
}
运行结果
每次调用MagicPlane的getPlane方法都会从容器中获取plane量化接口,bean,由于planeBean的作用域是prototype,因此每次都能返回新的plane实例。
如果将planeBean的作用域设置为默认的singleton,虽然也可以润兴,但是这个时候lookup所提供的方法注入就没有意义了。因为我们可以很轻松的编写一个magicPlane的实现类,用属性注入的方式达到相同的目的,因此lookup方法注入是有一定使用范围的,一般在希望通过一个singletonBean获取一个prototypeBean时使用
lookup方法的使用场景:一般在希望通过一个singletonBean获取一个prototypeBean时使用
方法替换MethodReplacer接口
使用某个Bean的方法替换另外一个Bean的方法。必须实现orspringframewor量化接口,beans.factory.support.MethodReplacer接口,重写reimplement方法。
package com.xgj.ioc.methodReplace;
public class Plane {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
public String getBrand() {
System.out.println('brand:' + brand);
return brand;
}
}
package com.xgj.ioc.methodReplace;
public class PilotOne {
public Plane getPlane() {
Plane plane = new Plane();
plane.setBrand('PilotOne-F22');
return plane;
}
}
package com.xgj.ioc.methodReplace;
import java.lang.reflect.Method;
import org.springframework.量化接口,beans.factory.support.MethodReplacer;
public class PilotTwo implements MethodReplacer {
public Object reimplement(Object obj, Method method, Object[] args)
throws Throwable {
Plane plane = new Plane();
plane.setBrand('PilotTwo-F35');
return plane;
}
}
配置文件
<量化接口,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.xsd'>
<量化接口,bean id='pilotOne' class='com.xgj.ioc.methodReplace.PilotOne'>
量化接口,bean>
<量化接口,bean id='pilotTwo' class='com.xgj.ioc.methodReplace.PilotTwo'/>
量化接口,beans>
测试类
package com.xgj.ioc.methodReplace;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MethodReplacerTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
'classpath:com/xgj/ioc/methodReplace/量化接口,beans.xml');
ctx.getBean('pilotOne', PilotOne.class).getPlane().getBrand();
}
}
运行结果
返回了第二个Bean的brand:PilotTwo-F3可见替换成功。
用于替换他人的Bean必须实现MethodReplacer接口,Spring利用该接口的方法去替换目标Bean的方法。
像lookup和methodreplacer高级功能,在实际中使用的很少,而属性注入、构造函数注入等反而在实际项目中使用的最多,我们了解即可。
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点