Spring官方文档重点摘录系列一:lookupmethod
其中一种实现方法是在methodA中通过beanFactory.getBean的方式来实现,如下:
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;
}
}
但这种方式需要耦合spring的api,依赖了spring框架。其实spring提供了一种灵活的方式处理此场景。
Lookup method injection
spring通过cglib字节码的方式为beanA动态创建一个子类,通过子类的复写methodA方法返回不同scope的bean需求。Lookup-method的限制:
1、类和方法都不能时final
2、Concrete methods are also necessary for component scanning, which requires concrete classes to pick up.-- 这句话没有看懂
3、A further key limitation is that lookup methods do not work with factory methods and in particular not with @Bean methods in configuration classes
意思就是不能和factory-method功能使用,以及不能在使用@Bean标注的method。因为这种情况下,bean的创建不是容器负责的,所以没有办法创建动态子类。
相对上面说到的CommandManager例子,spring 容器可以动态实现createCommand方法,同时CommandMananger不需要对spring框架有依赖。如下:
// 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();
}
一个目标类需要进行方法注入(比如当前例子中的CommandManager)需要满足下述格式要求:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
abstract是可以忽略的,如果是abstract方法,那么动态生成的子类会实现这个方法,否则那么子类将会复写这个方法。 --- 这个好像有点废话?
根据上面的CommandManager的配置方式如下:
<!-- a stateful bean deployed as a prototype (non-singleton) --><bean id="myCommand" 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="myCommand"/>
</bean>
通过注解的配置方式如下:
@Lookup("myCommand") protected abstract Command createCommand();
同时,spring可以通过返回对象的类型而推到出bean id而不需要显式指定,如:
@Lookup protected abstract MyCommand createCommand();
说说
- 之前查看源码的时候,留意到lookup-method,当时初步理解这大概是一个override的形式,没想到其解决的实际场景。比如在AutowiredAnnotationBeanPostProcessor的determineCandidateConstructors方法中,会判断方法是有标注了lookup注解,创建一个LookupMethpd添加到BeanDefinition中。如下:
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { @Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
LookupOverride override = new LookupOverride(method, lookup.value());
try {
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(beanName,
"Cannot apply @Lookup to beans without corresponding bean definition");
}
}
}
});
这里mdb.getMethodOverrides维护的应该就是所有lookup method方法列表。
实践场景
关联知识
1. 其他解决方案
1. ObjectFactory
2. Provider
3. ServiceLocatorFactoryBean
4. Arbitrary Method Replacement
相比lookup-method可以看作是一个加强版功能,可以替换任意方法。直接看栗子:
```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"/>
以上是 Spring官方文档重点摘录系列一:lookupmethod 的全部内容, 来源链接: utcz.com/z/513123.html