1.4.2. Dependencies and Configuration in Detail
Straight Values (Primitives, Strings, and so on)
直接值,这么翻译有点尬。它主要包含基本变量和字符串这些值。这些值通过
The idref element:
前面两种定义方式完全等价。第一种方式优于第二种,这是因为idref会在Container初始化时对引用的bean进行验证,可以及时发现错误;而第二种,只有在对象实例化时,才能发现错误。
References to Other Beans (Collaborators)
Container(ApplicationContext)之间可以存在层次关系,通过以下方式可以引用parent container中的bean:
class="org.springframework.aop.framework.ProxyFactoryBean">
Inner Beans
内部类的bean配置方式:
Collections:
,
[email protected]
[email protected]
[email protected]
just some string
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
Collection Merging
集合的合并,利用了bean定义继承的概念,在官方文档1.7中介绍了bean定义继承,本质是父bean定义作为模板,子bean定义可以继承父bean定义中的属性。
[email protected]
[email protected]
[email protected]
[email protected]
child中最后合并的adminEmails结果,如果key值在child中不存在,直接合并,如果已存在,那么使用child中的覆盖parent的值:
, , and
Strongly-typed collection
强类型集合,即指定了类型的集合,比如List
public class SomeClass {
private Map accounts;
public void setAccounts(Map accounts) {
this.accounts = accounts;
}
}
在初始化something时,value中指定的字符串("9.99","2.75","3.99")会被Spring组件在自动装配时自动转成Float类型。
Null and Empty String Values
相当于:
exampleBean.setEmail("");
相当于:
exampleBean.setEmail(null);
Compound Property Names
以下操作相当于设置something对象中的fred对象下面的bob对象的sammy的值,有点绕,实际上就是something依赖fred,fred依赖bob,bob依赖sammy。这块需要注意的是给sammy赋值前,需要程序员保证fred和bob均不为空,否则会报异常。
1.4.3. Using depends-on
有时对象间的依赖并不是显示的包含关系,所以在配置时并无依赖关系,但是如果我们在这种情况下,仍然需要保证某些bean先于其他的bean进行实例化,需要用到depends-on。如下示例,depends-on属性可以保证在实例化beanOne之前先实例化manager和accountDao:
1.4.4. Lazy-initialized Beans
正常情况下,ApplicationContext会在程序启动后初始化所有定义的bean。Spring提供了懒加载功能,当使用lazy-init="true"定义时,对象只有在第一次使用的时候才会被实例化。这种使用场景应该有不少:比如实例初始化消耗时间较多但是又不是必须启动时就初始化的对象,这样可以加快系统的启动速度。不过大多数时候我们应该不需要懒加载对象。示例如下:
全局的缺省设置方法如下:
1.4.5. Autowiring Collaborators
自动装配。该功能有两个好处:
- 减少指定properties 或者 constructor 的参数,简化xml配置
- 对象新增依赖的时,无需修改对象的配置,实际上也是简化了xml配置,因为不需要指定参数,所以必然不需要修改该bean的配置。
具体方法就是指定bean配置中的autowire属性:
you can specify the autowire mode for a bean definition with the autowire attribute of the
element
Autowiring modes:
Mode | Explanation |
---|---|
no | (Default) No autowiring |
byName | Autowiring by property name |
byType | Autowiring by property type |
constructor | Analogous to byType but applies to constructor arguments |
说明:
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such cases, all autowire candidates within the container that match the expected type are provided to satisfy the dependency.
Limitations and Disadvantages of Autowiring
使用自动装配,要么全局使用,要么不使用,否则只是个别对象进行自动装配,xml配置看起来会比较混乱。
the limitations and disadvantages of autowiring:
- property 和 constructor-arg优先级高于autowire
- 不支持自动装配简单属性:primitives, Strings, and Classes
- 自动装配在基于type(byType和constructor)的模式下可能引起歧义,并且无法直观的从xml配置观察对象间的协作关系
针对自动装配可能产生的歧义问题,有以下选择:
- 放弃自动装配,完全控制装配参数
- 设置bean的autowire-candidate属性为false,将会产生歧义的被装配的bean排除掉。autowire-candidate参数只影响基于type的装配
- 设置要被装配的bean的属性primary为true,那么直接装配时就会选择这个bean进行装配
- 基于注解的方式(在官方文档的后续章节,暂时知道有这种方式即可)
- 支持模式匹配来限制bean的装配,可以在beans元素中使用default-autowire-candidates指定正则表达式。比如default-autowire-candidates="*Repository"将会把所有Repository结尾的bean排除在外,不参与自动装配。该配置优先级低于前面的autowire-candidate
说明:autowire-candidate="false"只是用来限制配置该属性的bean无法注入到其他bean中,但是不影响自身装配其他的bean。
配置示例:
1.4.6. Method Injection
通常来讲,在一个系统中单例对象依赖单例对象,非单例对象依赖非单例对象时,Spring可以正常处理,但是假设一个单例对象依赖非单例对象:假设A对象是单例,A对象调用自己的process方法,但是process方法中每次需要创建新的B类型的实例执行相关操作,就不建议使用IoC的方式来管理B的实例了。如果还想用IoC的方式控制,接着看Lookup Method Injection是如何解决这个事情的。
Lookup Method Injection
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();
}
通过以上配置,Spring会通CGLIB动态生成CommandManager的子类,子类将实现createCommand方法,从而每次获取新的myCommand对象(这个子类以及子类createCommand方法都是Spring替我们实现的,Spring称之为方法注入)。这样,myCommand就又可以由Container来管理了。
Arbitrary Method Replacement
Spring支持替换类的方法,动态的将类中的方法替换成新的方法。实施过程如下。
替换前的原生类:
package replace;
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
return "";
}
// some other methods...
}
实现继承Spring接口MethodReplacer的类(这块感觉Spring设计的不太好,相当于业务代码与Spring代码产生了耦合,个人觉得好的方式是使用反射,而不是继承Spring的接口):
package replace;
import org.springframework.beans.factory.support.MethodReplacer;
import java.lang.reflect.Method;
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method method, Object[] args) throws Throwable {
String s = (String)args[0];
return s;
}
}
最后,xml配置:
String
这样,就完成了方法注入,原有类的行为随后发生改变。
arg-type参数设置时Spring支持的比较灵活,以下三种配置方式Spring都可以识别为字符串:
java.lang.String
String
Str
Spring提供的方法注入,我暂时唯一能想到的用处是:动态替换第三方库中类的方法。其他暂时没想到有什么用处。因为我认为类的行为应该是跟类本身匹配的,如果需要替换类的行为,那么说明类和行为并不匹配,或者考虑使用多态的方式来实现不同行为的子类来解决。而且,这个方式也有缺陷,如果类是final定义的,那么Spring会报错,导致无法注入,本质还是使用CgLib实现了方法注入。