方法注入
在大多数的应用场景下,多数的bean都是单例的。当这个单例的bean需要和另一个单例的或者非单例的bean协作使用的时候,开发者只需要配置依赖bean为这个bean的属性即可。 但是有时会因为bean具有不同的生命周期而产生问题。假设单例的bean A在每个方法调用中使用了非单例的bean B。容器只会创建bean A一次,而只有一个机会来配置属性。 那么容器就无法为每一次创建bean A时都提供新的bean B实例。
一种解决方案就是放弃IoC,开发者可以通过实现ApplicationContextAware接口让bean A对ApplicationContext可见。 从而通过调用getBean("B")来在bean A 需要新的实例的时候来获取到新的B实例。参考下面例子。
// 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;
}
}
查找方法注入
查找方法注入是容器覆盖管理bean上的方法的能力,以便返回容器中另一个命名bean的查找结果。查找方法通常涉及原型bean。 Spring框架通过使用CGLIB库生成的字节码来生成动态子类重写的方法实现此注入。
如果想让这个动态子类正常工作,那么Spring容器所继承的Bean不能是final的,而覆盖的方法也不能是final的。
对具有抽象方法的类进行单元测试时,需要开发者对类进行子类化,并提供抽象方法的具体实现。
组件扫描也需要具体的方法,因为它需要获取具体的类。
另一个关键限制是查找方法不适用于工厂方法,特别是在配置类中不使用@Bean的方法。因为在这种情况下,容器不负责创建实例,因此不能在运行时创建运行时生成的子类。
对于前面代码片段中的CommandManager类,Spring容器动态地覆盖createCommand()方法的实现。 CommandManager类不再拥有任何的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();
}
在包含需要注入方法的客户端类中 (在本例中为CommandManager)注入方法的签名需要如下形式:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
如果方法是abstract的, 那么动态生成的子类会实现该方法。否则,动态生成的子类将覆盖原始类定义的具体方法。例如:
<!-- 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>
当需要新的myCommand bean实例时,标识为commandManager的bean会调用自身的createCommand()方法.开发者必须小心部署myCommand bean为原型bean. 如果所需的bean是单例的,那么每次都会返回相同的myCommand bean实例.
另外,如果是基于注解的配置模式,你可以在查找方法上定义@Lookup注解,如下:
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
或者,更常见的是,开发者也可以根据查找方法的返回类型来查找匹配的bean,如下
public abstract class CommandManager {
public Object process(Object commandState) {
MyCommand command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract MyCommand createCommand();
}
注意开发者可以通过创建子类实现lookup方法,以便使它们与Spring的组件扫描规则兼容,同时抽象类会在默认情况下被忽略。这种限制不适用于显式注册bean或明确导入bean的情况。
另一种可以访问不同生命周期的方法是ObjectFactory/Provider注入。
您可能还会发现ServiceLocatorFactoryBean(在org.springframework.beans.factory.config包中)很有用。
替换任意方法
从前面的描述中,我们知道查找方法是有能力来覆盖任何由容器管理的bean方法的。开发者最好跳过这一部分,除非一定需要用到这个功能。
通过基于XML的元数据配置,开发者可以使用replaced-method元素来替换已存在方法的实现。考虑以下类,它有一个我们想要覆盖的名为computeValue 的方法:
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
实现org.springframework.beans.factory.support.MethodReplacer接口的类提供了新的方法定义,如以下示例所示:
/**
* 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方法的XML配置如下类似于以下示例:
<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"/>
您可以在<replaced-method/>元素中使用一个或多个 元素来指示被覆盖的方法的方法。当需要覆盖的方法存在重载方法时,必须指定所需参数。 为了方便起见,字符串的类型会匹配以下类型,它完全等同于java.lang.String
java.lang.String
String
Str
因为,通常来说参数的个数已经足够区别不同的方法,这种快捷的写法可以省去很多的代码。
标签:Spring,Object,bean,command,Command,方法,public,注入 From: https://blog.csdn.net/m0_54144956/article/details/140440314