Spring Dependencies Injection

旧城冷巷雨未停 提交于 2019-12-07 07:48:44

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.





标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!