zoukankan      html  css  js  c++  java
  • Spring的核心机制:依赖注入(xml方式)

     依赖注入的概念

    如果要在一个类中,使用另一个类,传统的方式是直接new:

    class  A{

      //......

      B  b=new B();

      //......

    }

    A类对象依赖于B类对象,如果没有B类对象,A类对象就不能正常工作,称为A依赖B。

    上面的方式会增加A类与B类的耦合,不利于项目后期的升级(扩展)、维护。

    在Spring中,B类的实例(被调用者),不再由A类(调用者)创建,而是由Spring容器创建,创建好以后,由Spring容器将B类实例注入A类实例中,称为依赖注入(Dependency Injection,DI)。

    原本是由A类主动创建B类对象(A类控制B类的创建),现在是Spring容器创建B类对象,注入A类对象中,A类被动接受Spring容器创建的B类实例,B类对象创建的控制权发生了反转,所以又叫做控制反转(Inversion of Control,IoC)。

    控制反转(IoC)是由依赖注入(DI)实现的,依赖注入又是由spring容器实现的,所以Spring容器又叫做Spring  IoC容器。。

    依赖注入是一种优秀的解耦方式,由Spring容器负责控制类(Bean)之间的关系,降低了类之间的耦合。

    常用的方式有2种:

    • 设值注入,也叫set方式注入
    • 构造方法注入

    设值注入

    将依赖作为成员变量,通过主调类的setter方法注入依赖。

    public class A {
        private B b;
    
        public void setB(B b) {
            this.b = b;
        }
        
        //......
    }

    xml配置:

        <bean name="b" class="com.chy.bean.B" />
        <bean name="a" class="com.chy.bean.A">
            <property name="b" ref="b"/>
        </bean>

    使用<property>注入依赖,name指定属性名(成员变量名),ref指定要注入的bean(value指定要注入的常量值)。

    如果要注入多个依赖,使用多个<property />即可。


    构造方法注入

    将依赖作为成员变量,通过主调类的构造方法注入依赖。

    public class A {
        private B b;
    
        public A(B b) {
            this.b = b;
        }
    
        //......
    }

    xml配置:

    <bean name="b" class="com.chy.bean.B" />
    <bean name="a" class="com.chy.bean.A">
            <constructor-arg name="b" ref="b" />
    </bean>

    一个<constructor-arg />注入一个参数,name指定构造方法中的形参名,ref指定要注入的bean(value指定要注入的常量值)。

    形参可用 name="形参名" 指定,也可以使用 index="形参表下标" 来指定(第一个参数 => 下标0)。

    如果有多个形参,使用多个<constructor-arg />即可,spring会调用对应的构造方法。


    不管是设值注入,还是构造方法注入,都是将依赖作为成员变量,所以有时候也把注入依赖叫做注入属性。


      

    依赖可分为3种类型:

    • 注入int、float、String之类的基本数据类型,使用value。

    比如根据学号查学生信息,需要注入一个int型的学号。

    spring会自动将值转换为需要的类型,比如需要的String,value="chy"会以String的形式注入。value="1",如果需要的是int,就转换为int注入,如果需要的是String,就转换为String注入。

    • 注入其他Bean的实例,使用ref。
    • 注入数组、集合、Properties等复杂类型

    注入复杂类型的依赖

    将复杂类型的数据数据作为成员变量:

        private Object[] arr;
        private List<Object> list;
        private Set<Object> set;
        private Map<String,Object> map;
        private Properties properties;

    设值注入需提供对应的setter方法,构造方法注入需提供对应的构造方法。

    设值注入:

     <bean name="a" class="com.chy.bean.A">
            <!-- 注入数组-->
            <property name="arr">
                <array>
                    <!-- 基本数据类型使用value,bean的实例使用ref,可嵌套其他复杂类型-->
                    <value>chy</value>
                    <ref bean="b" />
                </array>
            </property>
    
            <!-- 注入List -->
            <property name="list">
                <list>
                    <value>chy</value>
                    <ref bean="b" />
                </list>
            </property>
    
            <!-- 注入Set -->
            <property name="set">
                <set>
                    <value>chy</value>
                    <ref bean="b" />
                </set>
            </property>
    
            <!-- 注入Map-->
            <property name="map">
                <map>
                    <!-- Map的key只能是String,基本数据类型用value,其他Bean的实例用value-ref  -->
                    <entry key="id" value="1" />
                    <entry key="user" value-ref="b" />
                </map>
            </property>
    
            <!-- 注入Properties -->
            <property name="properties">
                <props>
                    <!-- 键、值都只能是String -->
                    <prop key="username">chy</prop>
                    <prop key="password">abcd</prop>
                </props>
            </property>
    </bean>

    <property name="">  name指定属性名(成员变量名)。

    数组、List、Set的配置方式是差不多的。

    构造方法注入:

    <constructor-arg name="arr">
                <array>
                    <value>chy</value>
                    <ref bean="b" />
                </array>
    </constructor-arg>

    配置方式和设值注入差不多,只不过将 property 换为 constructor-arg ,name是指定形参名。

    用的最多的是设值注入,因为很多时候都要修改成员变量的值,setter方法一般都要写,直接用setter方法设值注入,没必要再写带参的构造方法。


    使用自动装配注入其它Bean的实例

    原先注入其它bean的实例,需要使用<property />或<constructor />注入。

    使用自动装配后,不需要使用<property />、<constructor />,spring会自动在容器中找到满足要求的其它bean,注入进来。

    <bean name="a" class="com.chy.bean.A" autowire="byName" />

    可选的值:

    • no   默认值,不使用自动装配,如果要注入其它bean的实例,需要使用<property />或<constructor />。
    • byName   根据name来自动装配
    • byType  根据type来自动装配
    • constructor  根据构造函数形参类型进行byType方式的自动装配
    • default   使用全局默认的自动装配方式。

    byName和byType都能在设值注入中使用,constructor只能在构造方法注入中使用。

    byName

    public class A {
        private B b;
    
        public void setB(B b) {
            this.b = b;
        }
    }
    <bean name="b" class="com.chy.bean.B" />
    <bean name="a" class="com.chy.bean.A" autowire="byName" />

    A依赖B,A中有对应的setter方法。

    byName,name就是setter方法的方法名,去掉set,后面部分使用camel写法,比如setB() =>  b,

    spring会自动到容器中找到name="b"的bean,注入。

    name="b"的bean只能有一个,不然spring不知道要注入哪个。

    byType

    和byName差不多,也是要配合setter方法使用。不同的是:

    byType,type是形参表的参数类型。比如setB(B  b),参数类型是B,Spring自动找到class=“B”的bean,注入。

    class=“B”的bean只能有一个,不然spring不知道要注入哪个。

    constructor 

    public class A {
        private B b;
    
        public A(B b) {
            this.b = b;
        }
    }

    顾名思议,需要和构造方法注入搭配使用

    找到带参的构造器,根据参数类型,按照byType的方式注入依赖

    default   

    使用全局默认的自动装配方式。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
           default-autowire="byName">
    
        <bean name="b" class="com.chy.bean.B" />
        <bean name="a" class="com.chy.bean.A" autowire="default" />
    </beans>

    需要在根元素<beans>中设置全局默认的自动装配方式,所有default方式的自动装配都是使用 default-autowire 设置的方式进行装配。

    自动装配的贪婪原则

    自动装配会尽量多地注入依赖。

    比如constructor ,有2个构造方法:(B b)、(B b, C c),如果容器中有B、C的实例,则优先调用(B b, C c),会尽量多地注入依赖。

    自动装配的优点:一个属性就搞定,不必写大量的<property />或<constructor />。

    缺点:自动装配只能注入其它bean的实例,使用时有限制条件。(可以和注入基本类型、复杂类型的方式一起使用。实际上,注入基本类型、bean的实例、复杂类型都可以搭配使用。)


    使用SpEL注入依赖

    SpEL,即Spring Expression Language,spring表达式语言。

    使用SpEL可以注入基本类型,可以注入其它Bean,可以访问其它Bean的成员变量、调用其它Bean中的方法。

    使用示例:

        <bean name="score" class="com.chy.bean.Score">
            <property name="chinese" value="#{90}" />
            <property name="math" value="#{100}" />
            <property name="english" value="#{95}" />
        </bean>
        <bean name="student" class="com.chy.bean.Student">
            <property name="no" value="#{1}" />
            <property name="name" value="#{'chy'}" />
            <property name="score" value="#{score}" />
        </bean>

    SpEL放在#{ }中,数值型直接写,字符、字符串要加单引号,可以直接引用其它Bean。

    SpEL使用的是设值注入,所以需要提供setter方法,只能用<property />注入值,不能使用构造方法注入。

    不管值是什么类型,都只能用value,不能用ref。

    可以直接访问其它Bean的成员变量,比如 #{score.math} ,实质是调用对应的getter方法,所以需要提供getter方法。

    可以调用其它Bean的方法,比如 #{score.getMath()},如果该方法返回void,作为null处理。

  • 相关阅读:
    L1-050. 倒数第N个字符串
    全排列问题(递归)
    L2-014. 列车调度
    连通 OR 不连通(NOJ 1044)
    数三角形(codevs 3693)
    Min(BZOJ 1441)
    STL中heap用法
    军训分批(codevs 2751)
    团伙(codevs 2597)
    Subsequence(hdu 3530)
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/11111858.html
Copyright © 2011-2022 走看看