1.dependsOn
某些bean依赖一些bean,可以将依赖的ban先实例化和初始化。
2. lookup-method标签或@LookUp
单例模式的bean只会被创建一次,IoC容器会缓存该bean实例以供下次使用;原型模式的bean每次都会创建一个全新的bean,IoC容器不会缓存该bean的实例。那么如果现在有一个单例模式的bean引用了一个原型模式的bean呢?如果无特殊处理,则被引用的原型模式的bean也会被缓存,这就违背了原型模式的初衷,这时使用lookup-method注入可以解决该问题。
package com.mashibing.methodOverrides.lookup;
public class Fruit {
public Fruit() {
System.out.println("I got Fruit");
}
}
package com.mashibing.methodOverrides.lookup;
public class Apple extends Fruit {
public Apple() {
System.out.println("I got a fresh apple");
}
}
package com.mashibing.methodOverrides.lookup;
public class Banana extends Fruit {
public Banana() {
System.out.println("I got a fresh bananer");
}
}
package com.mashibing.methodOverrides.lookup;
public abstract class FruitPlate{
// 抽象方法获取新鲜水果
public abstract Fruit getFruit();
}
<?xml version="1.0" encoding="UTF-8"?>
<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="apple" class="com.mashibing.methodOverrides.lookup.Apple" scope="prototype"/>
<bean id="banana" class="com.mashibing.methodOverrides.lookup.Banana" scope="prototype" />
<bean id="fruitPlate1" class="com.mashibing.methodOverrides.lookup.FruitPlate">
<lookup-method name="getFruit" bean="apple"/>
</bean>
<bean id="fruitPlate2" class="com.mashibing.methodOverrides.lookup.FruitPlate">
<lookup-method name="getFruit" bean="banana"/>
</bean>
</beans>
关键点:
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
原理是:使用cglib生产代理类,复写方法。CglibSubclassingInstantiationStrategy#intercept
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// Cast is safe, as CallbackFilter filters are used selectively.
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
Assert.state(lo != null, "LookupOverride not found");
Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all
if (StringUtils.hasText(lo.getBeanName())) {
// 代理之后,原型bean每次都新建
return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
this.owner.getBean(lo.getBeanName()));
}
else {
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
this.owner.getBean(method.getReturnType()));
}
}