例如A的scope是 Singleton ,B的scope是Prototype,当A依赖B时,B实例会在第一次初始化请求创建,之后的对A的调用间接依赖的B仍旧是同一实例,这并非B所声明的scope=Prototype含义。
// a class that uses a stateful Command-style class to perform some processing package fiona.apple; // Spring-API imports import org.springframework.beans.BeansException; import org.springframework.context.Applicationcontext; import org.springframework.context.ApplicationContextAware; public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; public Object process(Map commandState) { // grab a new instance of the appropriate Command Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } protected Command createCommand() { // notice the Spring API dependency! return this.applicationContext.getBean("command", Command.class); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
上述createCommand方法里调用了getBean方法改变了依赖注入方式。但是还有一点“瑕疵”:依赖了ApplicationContext。这种任务Spring也提供了,因为诞生初衷就是为了减少代码的耦合程度,所以有了后来的控制反转。Look up method解决了这个问题。只要对每个要使用getBean代码的方法配置一个Bean(不支持一个方法对应多个Bean),注意替换的方法是无参的
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- inject dependencies here as required --> </bean> <!-- commandProcessor uses statefulCommandHelper --> <bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="command"/> </bean>
现在代码不再依赖于Spring
package fiona.apple; // no more Spring imports! 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(); }
很少使用但很强大的同宗replace method
lookup method只是替换了getBean这样的简单代码,而replace method它将深入到指定bean之后的方法调用中,即MethodReplacer的方法reimplement,这里可以做更多的事,显然它支持并且一定比较可能重载的方法。
/** meant to be used to override the existing computeValue(String) implementation in MyValueCalculator */ public class ReplacementComputeValue implements MethodReplacer { public Object reimplement(Object o, Method m, Object[] args) throws Throwable { // get the input value, work with it, and return a computed result String input = (String) args[0]; ... return ...; } }
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator"> <!-- arbitrary method replacement --> <replaced-method name="computeValue" replacer="replacementComputeValue"> <arg-type>String</arg-type> </replaced-method> </bean> <bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
实现
之前提到过AbstractBeanFactory,其子类AbstractAutowireCapableBeanFactory实现了instantiateBean方法
再进入SimpleInstantiationStrategy,可以看到如果有方法覆盖将调用instantiateWithMethodInjection,否则使用反射机制实例化
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (beanDefinition.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; synchronized (beanDefinition.constructorArgumentLock) { constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class clazz = beanDefinition.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() { public Constructor run() throws Exception { return clazz.getDeclaredConstructor((Class[]) null); } }); } else { constructorToUse = clazz.getDeclaredConstructor((Class[]) null); } beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Exception ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(beanDefinition, beanName, owner); } }
SimpleInstantiationStrategy子类CglibSubclassingInstantiationStrategy实现了instantiateWithMethodInjection方法,显然method注入的两种方式都是使用Cglib实现的。
setSuperclass:设置要代理的父类
setCallbackFilter:设置过滤器,有一个accept方法返回拦截器的索引值:
lookup method 该方法使用lookup method
replace method 改方法使用replace method
not found 不对方法拦截
setCallbacks:设置拦截器
public Object instantiate(Constructor ctor, Object[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.beanDefinition.getBeanClass()); enhancer.setCallbackFilter(new CallbackFilterImpl()); enhancer.setCallbacks(new Callback[] { NoOp.INSTANCE, new LookupOverrideMethodInterceptor(), new ReplaceOverrideMethodInterceptor() }); return (ctor == null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args); }
lookup method拦截
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); return owner.getBean(lo.getBeanName()); } }
replace method拦截
private class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable { ReplaceOverride ro = (ReplaceOverride) beanDefinition.getMethodOverrides().getOverride(method); // TODO could cache if a singleton for minor performance optimization MethodReplacer mr = (MethodReplacer) owner.getBean(ro.getMethodReplacerBeanName()); return mr.reimplement(obj, method, args); } }