-
depends-on
的使用一般情况下,我们使用
<ref/>
元素来定义bean之间的依赖关系,但是有时候bean之间并不直接依赖。depends-on
属性可以显式的强制一个或多个被依赖的beans在使用依赖的bean初始化之前被初始化。<bean id="beanOne" class="ExampleBean" depends-on="manager"/> <bean id="manager" class="ManagerBean" />
manager
将在beanOne
之前被创建。
多个依赖:<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"> <property name="manager" ref="manager" /> </bean> <bean id="manager" class="ManagerBean" /> <bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
depends-on
属性的值为一个依赖列表,bean名称之间用,
、;
或者是空格隔开。depends-on
属性还会控制有依赖关系的bean的销毁顺序,上面的配置中,beanOne
先被销毁,然后销毁manager
和accountDao
。 -
懒加载bean
ApplicationContext
默认使用预加载,将bean的创建作为容器初始化进程的一部分。然而,我们可以通过lazy-init
属性将bean设置为懒加载。<!-- lazy将会在初次需要是被创建 --> <bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
也可以在容器级别设置为懒加载:
<beans default-lazy-init="true"> <!-- 这里定义的bean全部为懒加载 --> </beans>
-
自动装配
Spring容器可以自动装配合作bean的依赖关系。我们可以让Spring通过检测
ApplicationContext
容器的内容来达到自动解析依赖的目的。自动装配有一下优点:- 自动装配可以显著的减少配置bean属性或者是构造器参数的需要;
- 当我们的对象改变时,自动装配可以更新配置。
我们通过
<bean>
元素的autowire
属性来设置自动装配,自动装配有4种模式:模式 解释 no
(默认)不使用自动装配,bean之间的依赖必须使用 ref
来定义。在大型系统中,推荐使用该模式。因为明确的指定合作者可以带来更好的控制和清晰的系统结构。byName
通过名字实现自动装配。Spring在容器中寻找与属性名相同的bean,并将其注入。(需要有对应的修改器方法) byType
通过属性类型自动装配。如果容器中恰好有一个与属性类型匹配的bean,这个bean就会被注入。如果有多个匹配的bean,将会抛出一个重大的异常,该异常指示我们这个bean不应该使用 byType
模式。如果没有匹配的bean,将不会做任何操作。constructor
与 byType
模式类似,只不过这里按类型将bean自动装配给bean的构造参数。匹配到多个或没有都将抛出异常。(在基于构造器的依赖注入中有效)自动装配的限制于缺点:
如果要使用自动装配,那么最好整个项目都使用自动装配。仅仅在几个bean的定义中使用自动装配的话,可能会使开发人员混淆。
- 在
property
和constructor-arg
中明确指出依赖总是会覆盖自动装配。我们不能自动装配基本类型,字符串和数组这样的简单对象。 - 尽管Spring在可能造成无法预测的结果的模糊情况下不会采用猜测的方式自动装配一个bean,自动装配也没有显式装配准确。
- 那些从Spring容器中产生文档的工具无法获取装配信息。
在以后的开发过程中,我们有一下几个选择:
- 抛弃自动装配,使用显式装配
- 设置
autowire-candidate
为false
,避免将该bean自动装配 - 将
<bean>
元素的primary
属性设置为true
,使该bean成为首选被装入的bean - 使用基于注解的配置来实现更加细粒度的控制。
在自动装配中,排除一个bean的注入:
在按类型自动装配模式中,可以将
autowire-candidate
的值设为false
,这样,容器在自动装配时就会忽略这个bean。我们还可以在
<beans>
元素中,为defualt-autowire-candidate
设置值,按bean的name
进行样式匹配(patter-matching)。default-autowire-candidate
的值可以是以,
分开的列表。
如我们要自动装配name以Repository
结尾和Service
结尾的bean,那么这个值就是*Repository,*Service
。 -
方法注入
如果我们有一个单例bean
A
,需要调用多例beanB
的方法,容器没有办法在A
需要调用方法时,都提供一个最新的B
实例。解决办法就是让A
继承ApplicationContextAware
接口,并调用getBean("B")
方法,
在每次A
需要B
时都从容器获取最新的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; } }
这样做并不理想,因为它使得我们的业务代码和Spring框架耦合了。方法注入(Method Injection) 这一Spring IoC容器先进的特性让我们解决这一用例更加干净利落。
查找方法注入
查找方法注入(lookup method injection) 让容器覆盖bean的方法,并将查找结果返回给另外一个bean。Spring框架通过
CGLIB
包的字节码生成工具来动态的生成一个子类,来实现或者覆盖返回查询结果的方法。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(); }
因为容器会继承
CommondManager
,所以不能将该类声明为final
;因为子类要实现或者覆盖createCommand
方法,所以这个方法也不能声明为final
。被注入的方法应该有这样的签名格式:<public|protected> [abstract] <return-type> theMethodName(no-arguments)
配置信息:
<!-- 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>
当
commondManager
bean需要一个新的myCommand
实例时,就调用自己的createCommand
方法。与之对应的,基于注解的配置模式中,使用
@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) { Command command = createCommand(); command.setState(commandState); return command.execute(); } @Lookup //不指明目标bean protected abstract Command createCommand(); }
任意方法替换:
另外一种少见的方法注入形式:将一个bean的方法替换为里一个实现方法。
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 { /** *obj - the instance we're reimplementing the method for *method - the method to reimplement *args - arguments to the method *Returns: return value for the method */ String input = (String) args[0]; ... return ...; } }
为原始类指定覆盖方法的bean定义类似于下列所示:
<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"/>
03、IoCContainer-3 依赖
最新推荐文章于 2023-01-24 14:31:52 发布