spring的依赖注入

目录

spring与IoC

IoC:控制反转,将由代码操纵的对象控制权,交给第三方容器,反转给第三方容器。这种对象依赖的关系管理方式,称作IoC。IoC是一个思想,概念。比较 著名的两种方式:

  1. DL(Dependency Lookup)依赖查找,典型的是JNDI。java名称与服务接口。
  2. DI(Dependency Injection)依赖注入。是目前最优秀的接耦合方式。典型应用spring。

spring的DI

依赖注入,即:为属性赋值。

xml实现

1)设值注入

底层调用属性的setter方法进行赋值,所以实体类属性一定要有setter方法。

<bean id="student" class="com.abc.di01.Student">
    <property name="age" value="20"/>
    <property name="name" value="张三"/>
    <property name="school" ref="mySchool"/>
</bean>

使用property标签给对应属性赋值,或者使用"ref"指定一个引用类型;

首先调用无参数构造器生成对象。然后调用setter方法给对象属性赋值。如果定义的有参数的构造器,则需要添加一个无参数的构造器,以方便其创建对象。

2)构造注入

底层调用带参数的构造器。

<!--直接给对应的构造方法参数赋值-->
<bean id="student" class="com.abc.di02.Student">
    <constructor-arg name="age" value="20"/>
    <constructor-arg name="name" value="李四"/>
    <constructor-arg name="school" ref="mySchool"/>
</bean>
<!--使用索引方式赋值-->
<bean id="student" class="com.abc.di02.Student">
    <constructor-arg index="0" value="李四"/>
    <constructor-arg index="1" value="20"/>
    <constructor-arg index="2" ref="mySchool"/>
</bean>
<!--直接省略索引下标,进行赋值-->
<bean id="student" class="com.abc.di02.Student">
    <constructor-arg value="李四"/>
    <constructor-arg value="20"/>
    <constructor-arg ref="mySchool"/>
</bean>

使用标签,添加属性的值即可。

中index的使用按照构造参数的顺序进行赋值(第二种)。也可以将索引的标签省略掉(第三种)。

在实际使用中还是使用name-value这种,看上去比较直观清晰。

3)命名空间注入

两种:

  1. p命名空间(property)注入:setter赋值
  2. c命名空间(constructor)注入:构造方法赋值(注意写无参构造方法)

实际上底层依然调用的是setter和构造器方法。

首先需要引用约束:

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

idea可以自动引入;

<bean id="student" class="com.abc.di03.Student" p:age="19" p:name="小明" p:school-ref="mySchool"/>
<bean id="student" class="com.abc.di04.Student" c:age="16" c:name="小红" c:school-ref="mySchool"/>

4)数组与集合属性注入

数组,集合中可以存放基本的数据类型和对象类型;同样:在map中,键和值可以存放基本数据类型和对象。

在案例中数组已经定义存放String;

<bean id="some" class="com.abc.di05.Some">
    <!--数组赋值-->
    <property name="names">
        <array>
            <value>张三</value>
            <value>李四</value>
            <value>王五</value>
        </array>
    </property>
    <!--List-->
    <property name="myList">
        <list>
            <value>河南</value>
            <value>河北</value>
        </list>
    </property>
    <property name="schools">
        <list>
            <ref bean="aynu"/>
            <ref bean="tsinghua"/>
        </list>
    </property>
    <!--set集合赋值-->
    <property name="mySets">
        <set>
            <value>本科</value>
            <value>硕士</value>
            <value>博士</value>
        </set>
    </property>
    <!--map集合赋值-->
    <property name="myMap">
        <map>
            <entry key="mobile" value="123456"/>
            <entry key="QQ" value="654321"/>
        </map>
    </property>
    <!--properties集合-->
    <property name="myPros">
        <props>
            <prop key="email">123456@qq.com</prop>
            <prop key="address">文明大道</prop>
        </props>
    </property>
</bean>

可以看到使用标签为数组赋值;list中:;set中:;map中使用关联关系;在Properties中标签可以写多个关联;

要注意
list和set集合的区别,list中可以允许重复元素的存在,在set中不允许重复元素存在;set十分接近“数学中集合”的概念--无序不可重复;

properties,map中的键也不能重复,重复的话对应的值就会覆盖

向数组中赋值时可以将值写成下面的简写方式:

<property name="names" value="张三,李四">
    <!--<array>
        <value>张三</value>
        <value>李四</value>
        <value>王五</value>
    </array>-->
</property>

必须为基本数据类型并且需要使用英文的逗号。

5)域属性自动注入

域属性:一个对象属性

域属性自动注入:可以通过指定域属性的类型注入或者通过指定域属性名称两种方式注入;

student类的属性:

private String name;
private int age;
//域属性
private School school;//也需要有setter方法

配置文件:

<!--
    byType:同种类型的对象(包括子类的对象)只能有一个
    byName:注入的bean的id和域属性的属性名相同
-->
<bean id="student" class="com.abc.di06.Student" autowire="byName">
    <property name="age" value="20"/>
    <property name="name" value="张三"/>
</bean>
<bean id="school" class="com.abc.di06.MiddleSchool">
    <property name="sname" value="一中"/>
    <property name="address" value="文明大道"/>
</bean>

autowire="byName"

通过指定域属性的id进行自动注入,要求域属性名要和如上id="school"的id值相等;

如果使用autowire="byType"通过域属性的类型注入,那么同种类型的对象只能有一个,只要满足"is -a"关系,即:包括同种子类对象和它自身也不行;

6)SPEL注入

主要使用#{},可调用属性,方法。

<!--首先定义一个类,注入属性,T调用Math类-->
<bean id="person" class="com.abc.di07.Person">
    <property name="pname" value="张三"/>
    <property name="page" value="#{T(java.lang.Math).random()*100}"/>
</bean>
<!--可以将person中的值注入到student中-->
<bean id="student" class="com.abc.di07.Student">
    <property name="name" value="#{person.pname}"/>
    <!--<property name="age" value="#{person.page>30?30:person.page}"/>-->
    <property name="age" value="#{person.computeAge()}"/>
</bean>

实例:将一个对象中的值注入另一个对象中

如果需要简单判断,可以使用三模运算符(注释);如果复杂运算可以在调用的对象中写一个方法并调用;

注解简单实现

首先在主配置文件中配置注解扫描:

<!--注册组件扫描器-->
<context:component-scan base-package="com.abc.di01"/>
  1. 设值注入

@Component()注解,声明组件相当于在注解中定义一个bean;

@Value()注解,用于设置注入相当于bean里面的property,给这个bean添加属性;需要有属性的setter();

//在注解中如果只有"value"一个参数,可以将value省略,只留下value的值;
@Component("mySchool")
public class School {
    @Value("一中")
    private String sname;

    public void setSname(String sname) {
        this.sname = sname;
    }
}
  1. 域属性自动注入

    @Autowired:通过类型自动注入;

    @Qualifier()通过域对象的名称进行注入

@Component(value = "student")
public class Student {
    @Value("小刘")
    private String name;
    @Value("18")
    private int age;
    //byType方式自动注入
    //@Autowired
    //byName方式自动注入
    //@Qualifier("mySchool")
    private School school;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSchool(School school) {
        this.school = school;
    }
}
上一篇:Java面向对象之静态属性静态方法、访问权限、getter与setter


下一篇:如何利用缓存机制实现JAVA类反射性能提升30倍