方法注入
对于大部分的用户来说,容器中多数的bean是singleton的。当一个singleton的bean需要同另一个singleton的bean合作(使用)时,或者一个非singleton的bean需要同另外一个非singleton的bean合作的时候,通过定义一个bean为另一个bean的属性来处理这种依赖关系就足够了。然而当bean的生命周期不同的时候就有一个问题。想象一下一个singleton bean A ,或许在每次方法调用的时候都需要使用一个non-singleton bean B。容器仅仅会创建这个singleton bean A一次,因此仅仅有一次的机会去设置它的属性。因此容器没有机会每次去为bean A提供新的bean B实例。
一个解决这个问题的方法是放弃一些反向控制。Bean A可以通过实现BeanFactoryAware知道容器的存在,使用编程的手段在需要的时候通过调用getBean(“B”)来向容器请求新的bean B实例。因为bean的代码知道Spring并且耦合与Spring,所以这通常不是一个好的方案。
方法注入,BeanFactory的高级特性之一,可以以清洁的方式处理这种情况以及其他一些情况。
Lookup方法注入
Lookup方法注射指容器能够重写容器中bean的抽象或具体方法,返回查找容器中其他bean的结果。被查找的bean在上面描述的场景中通常是一个non-singleton bean (尽管也可以是一个singleton的)。Spring通过使用CGLIB库在客户端的类之上修改二进制码,从而实现上述的场景要求。
包含方法注入的客户端类,必须按下面的形式抽象(具体)定义方法:
protected abstract SingleShotHelper createSingleShotHelper();
如果方法不是抽象的,Spring就会直接重写已有的实现。在XmlBeanFactory的情况下,可以使用bean定义中的lookup-method属性来指示Spring去注入/重写这个方法,以便从容器返回一个特定的bean。
举个例子说明:
bean="singleShotHelper"/>
...
当myBean需要一个新的singleShotHelper的实例的时候,它就会调用它自己的createSingleShotHelper方法。值得注意的是:部署beans的人员必须小心地将singleShotHelper作为一个non-singleton部署(如果确实需要这么做)。如果它作为一个singleton(除非明确说明,否则缺省就是singleton)而部署,同一个singleShotHelper实例将会每次被返回。
注意Lookup方法注射能够同构造函数注射结合(对创建的bean提供可选的构造函数参数),也可以同setter方法注射结合(在创建的bean之上设置属性)。
任意方法的替换
另一种方法注射没有lookup方法注入用的多,它用另一个方法实现替换被管理bean的任意一个方法。用户可以放心跳过这一节(这是个有点高级的特性),除非这个功能确实需要。
在一个XMLBeanFactory中,对于一个被部署的bean,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 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) arg[0];
...
return ...;
}
}
部署原始的类和指定方法重写的BeanFactory部署定义像下面所示的:
replaced-method元素中的一个或多个arg-type元素用来表示,这个被重载方法的方法签名。注意,参数的签名只有在方法被重载并且该方法有多个不同形式的时候才真正需要。为了方便,参数的类型字符串可以使全限定名的子字符串。比如,以下的都匹java.lang.String。
java.lang.String
String
Str
因为参数的个数通常就足够区别不同的可能,所以仅仅使用匹配参数的最短的字符串能够节省很多键入工作。
使用depends-on
对于大多数的情况,一个bean被另一个bean依赖,是由于这个bean是否被当作其他bean的属性来表达的。在XmlBeanFactory中,它是通过ref元素来完成的。与这种方式不同的是,有时一个知道容器的bean仅仅会被给与它所依赖的id(使用一个字符串值或等价的idref元素)。接着第一个bean就以编程的方式向容器请求它的依赖。在两种情况下,被依赖的bean都会在依赖它的bean之前被恰当地初始化。
对于相对罕见的情况,beans之间的依赖不够直接(举例,当一个类中的静态初始块需要被触发,比如数据库驱动的注册),depends-on元素可以用来在初始化使用这个元素的bean之前,强制一个或多个beans初始化。
下面是一个配置的例子:
自动装配协作对象
BeanFactory能够自动装配合作bean之间的关系。这就意味着,让Spring通过检查BeanFactory的内容来自动装配你的bean的合作者(也就是其他的bean)。自动装配功能有5种模式。自动装配可以指定给每一个bean,因此可以给一些bean使用而其他的bean不再自动装配。通过使用自动装配,可以减少(或者消除)指定属性(或构造参数)的需要,显著节省键入工作。在XmlBeanFactory中,使用bean元素的autowire属性来指定bean定义的自动装配模式。以下是允许的值。
模式 |
解释 |
no |
不使用自动装配。Bean的引用必须通过ref元素定义。这是默认的配置, |
byName |
通过属性名字进行自动装配。这个选项会检查BeanFactory,查找一个与 |
byType |
如果BeanFactory中正好有一个同属性类型一样的bean,就自动装配这个 |
constructor |
这个同byType类似,不过是应用于构造函数的参数。如果在BeanFactory中不是恰好有一个bean与构造函数参数相同类型,则一个致命的错误会产生。 |
autodetect |
通过对bean检查类的内部来选择constructor或byType。如果找到一个缺省的构造函数,那么就会应用byType。 |
注意:显示的指定依赖,比如property和constructor-arg元素,总汇覆盖自动装配。自动装配的行为可以和依赖检查结合使用,依赖检查会在自动装配完成后发生。
注意:正如我们已经提到过的,对于大型的应用,自动装配不鼓励使用,因为它去除了你的合作类的透明性和结构。