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();


说说

  1. 之前查看源码的时候,留意到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

回到顶部