标题来自于CglibSubclassingInstantiationStrategy
看spring IOC 实现,bean-definition 实例化过程中,有这么个过程,根据override method 决定用Cglib 还是JDK 反射。
/**
* Return an instance of the bean with the given name in this factory.
* 根据MethodOverrides决定使用反射还是cglib 来实例化。why ???
* /
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (beanDefinition.getMethodOverrides().isEmpty()) {
// ...
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
误会了,此MethodOverride 非 @Override.
......
那么,MethodOverride 来自哪里?
先看看MethodOverride 子类LookupOverride、ReplaceOverride。
这些类型对象会在解析spring配置xml 过程中构造, 参考BeanDefinitionParserDelegate.parseLookupOverrideSubElements()。
......
那么,为什么会有配置MethodOverride 的需求?
通过参考spring.io 的文档,确实有一种情景,需要执行方法中入参全新的instance 而不是singletons instance。直接上原文:
In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean, or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other. A problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container only creates the singleton bean A once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.
solution 1. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean("B") call to the container ask for (a typically new) bean B instance every time bean A needs it.
solution 2. Method Injection, a somewhat advanced feature of the Spring IoC container, allows this use case to be handled in a clean fashion.
......
那么动态的method 注入bean 是怎么实现?
直接上源码,强大的Cglib 用来实现动态method inject简直完美:
/**
* Create a new instance of a dynamically generated subclass implementing the
* required lookups.
*/
public Object instantiate(Constructor
ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackFilter(new CallbackFilterImpl()); // 决定是否执行动态method inject
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE, // case1: 不响应
new LookupOverrideMethodInterceptor(), // case2: 执行动态method inject
new ReplaceOverrideMethodInterceptor() // case3: 动态替换method
});
return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
}
/**
* CGLIB MethodInterceptor to override methods, replacing them with an
* implementation that returns a bean looked up in the container.
*/
private class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
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) beanDefinition.getMethodOverrides().getOverride(method);
// 方法调用时获取new bean
return owner.getBean(lo.getBeanName());
}
}
demo/example,怎么用?
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method???
protected abstract Command createCommand();
}