Spring Dependencies Injection
1、construtor argsInjection
1.1 ref注入
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}
此时会根据类型匹配相应的构造器参数,进行注入
1.2 指定type类型 注入
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
1.3 指定index注入
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
1.4 使用注解注入
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
2、Setter-based dependency injection
是时候用构造器注入,啥时候用setter哪,一个经验说:必须的参数需要构造器注入,其他的可以用setter,但是,也可以用@Required annotation去显示指定必须的参数
2.1 简单的set注入
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
<bean id="simpleMovieLister" class = "...">
<property name = "movieFinder" ref = "movieFinder"></property>
</bean>
大量的setter注入需要灰常多的的非空判断,所以spring的官方推荐是用constructor的注入,如果需要传入的参数过多,建议使用工厂方法,哦耶!
3、依赖解析流程
第一步:
ApplicationContext创建,使用通过xml,java code ,annotation配置的元数据进行初始化beandefinition,
(The ApplicationContext is created and initialized with configuration metadata that describes all
the beans. Configuration metadata can be specified via XML, Java code, or annotations.)
第二步:
获取到每个通过构造函数,setter,property,工厂方法注入的属性(ref,基本数据类型),在这个bena被创建的时候赋值给他
(For each bean, its dependencies are expressed in the form of properties, constructor arguments, or
arguments to the static-factory method if you are using that instead of a normal constructor. These
dependencies are provided to the bean, when the bean is actually created.)
第三步:
每个属性或构造函数参数的定义的参数都是一个集合,或者基本数据类型,或者容器中另外一个bean的引用。
(Each property or constructor argument is an actual definition of the value to set, or a reference to
another bean in the container)
第四步:
每个构造器参数或者属性都是被转化为实际的类型,默认的spring会转化value为任何一个基本类型int,long,boolean,String等
( Each property or constructor argument which is a value is converted from its specified format to the
actual type of that property or constructor argument. By default Spring can convert a value supplied
in string format to all built-in types, such as int, long, String, boolean, etc.)
循环依赖(Circular dependencies)注入
加入你顶一个class A,他的构造器里面需要参数为Class B,同时,class B的构造器需要一个Class A这时候Spring注入会陷入循环当中,抛出一个BeanCurrentlyInCreationException的异常
咋办,虽然推荐用构造器注入好,但是这种情况下,你要变通下,用setter注入不就好了吗,ok!
这是一个经典的哲学问题,先有鸡还是先有蛋(a classic chicken/egg scenario)
虽Spring会有问题,但是通常情况下你要相信Spring的解决能力,当在load的时候他不会影响整个系统的因为单个bean的注入问题,只有在整个bean被创建的时候才会报错,值得学习的思想
属性 idref
idef可以在容器初始化之前经行验证,制定的id的ref对象是否存在
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
属性ref
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<ref id="theTargetBean" />
</property>
</bean>
引用父级的元素
<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
内部类
这个内部类显示去配置声明一个bean元素时候不需要指定id 或者name,容器不会去需要这个,而且scope也不需要
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
集合Collections
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
自动合并父级集合属性,merge
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
depends-on
ref有时候不太强大,当你需要初始化你的类之前,需要确保你的引用类一定被先初始化,这时候该标签有了一个强大力量
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
The depends-on attribute in the bean definition can specify both an initialization time dependency
and, in the case of singleton beans only, a corresponding destroy time dependency. Dependent
beans that define a depends-on relationship with a given bean are destroyed first, prior to the
given bean itself being destroyed. Thus depends-on can also control shutdown order.
来源:oschina
链接:https://my.oschina.net/u/867830/blog/408242