DI注入

spring中是通过DI实现IOC的, 今天我们来学习DI

 

目录

简介

   两种手段

di的语法分类

实现步骤

    1. 创建maven项目

    2. 加入maven依赖

    3. 创建类(接口和它的实现类)

    4. 创建spring需要的配置文件

    5. 测试spring是否成功创建对象

set注入

set注入(设值注入)实例

        简单类型的set注入实例

        引用类型的set注入

构造注入 : 在构造实例的同时, 完成对象的实例化

配置文件方式总结 

    简单类型 : spring中规定基本数据类型和String都是简单类型

        1. set注入(注入就是设值)

        2. 构造注入 : 调用有参数的构造方法

引用类型的自动注入

    1. byName(按名称注入)

    2. byType(按类型注入) 

    测试byName

    测试byType


简介

di : 依赖注入, 表示创建对象, 给属性赋值

   两种手段

       1. 配置文件的方式: 使用标签和属性完成, 叫做基于XML的di实现

       2. 注解: 使用spring中的注解完成, 叫做基于注解的di实现

di的语法分类

    1. set注入(设值注入): spring中调用类的set方法, 用set方法可以实现属性的赋值

    2. 构造注入, spring调用类的构造方法, 创建对象, 在构造方法中完成赋值

实现步骤

    1. 创建maven项目

    2. 加入maven依赖

        spring依赖, 版本为 5.2.5

            <!-- Spring核心依赖 -->
            <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
            </dependency>

        Junit依赖(单元测试)

    3. 创建类(接口和它的实现类)

        和没有使用框架一样, 就是普通的类

    4. 创建spring需要的配置文件

        声明类的信息, 这些类由spring创建和管理

        通过spring的语法, 完成属性的赋值

    5. 测试spring是否成功创建对象

set注入

set注入(设值注入)实例

    简单类型 : spring中规定基本数据类型和String都是简单类型

        简单类型的set注入实例

        Student.java如下

        public class Student {
            private String name;
            private int age;

            public void setName(String name) {
            System.out.println("调用name的set方法");
            this.name = name;
            }

            public void setAge(int age) {
            System.out.println("调用age的set方法");
            this.age = age;
            }

            @Override
            public String toString() {
            return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
            }
        }

        applicationContext.xml文件如下:

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


        <!--    声明student对象-->
        <!--
            di : 给属性赋值
            简单类型 : spring中规定基本数据类型和String都是简单类型
            1. set注入(注入就是设值) : spring调用类的set方法(没有set方法会运行时异常), 可以在set方法中完成属性赋值
            简单类型的set注入
            <bean id="xx" class="yyyy">
                一个property只能给一个属性赋值
                <property name="属性的名字" value="属性的值" />
            </bean>
        -->
            <bean id="myStudent" class="org.example.ba01.Student"><!--相当于调用无参构造-->
            <property name="name" value="张三" /><!--相当于调用name的set方法 setName("张三")-->
            <!--不管value是什么类型, 必须加双引号, 这个是xml文件的规定-->
            <property name="age" value="20" /><!--相当于调用age的set方法 setAge(20)-->
            </bean>

        </beans>

        测试代码如下:

        public class MyTest {

            @Test
            public void test01() {
            String config = "ba01/applicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(config);

            // 从容器中获取myStudent对象
            Student myStudent = (Student) ac.getBean("myStudent");
            System.out.println(myStudent);
            }

        }

        控制台打印结果如下:

        调用name的set方法

        调用age的set方法

        Student{name='张三', age=20}

        前面两句说明标签<property>实际上是spring容器自己调用set方法

        重要问题 : 如果没有属性, 但是有set方法, spring可以执行吗

            给出例子:

            测试代码不变, 

            Student.java如下:

           public class Student {
                private String name;
                private int age;

                public void setName(String name) {
                System.out.println("调用name的set方法");
                this.name = name;
                }

                public void setAge(int age) {
                System.out.println("调用age的set方法");
                this.age = age;
                }

                // 注意这里, 没有email属性, 但是有set方法

                public void setEmail(String string) {
                System.out.println("执行setEmail方法");
                }

                @Override
                public String toString() {
                return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
                }
            }

            applicationContext.xml文件如下:

                <bean id="myStudent" class="org.example.ba01.Student"><!--相当于调用无参构造-->
                <property name="name" value="张三" /><!--相当于调用name的set方法 setName("张三")-->
                <property name="age" value="20" /><!--相当于调用age的set方法 setAge(20)-->
                <property name="email" value="123@123.com" />
                </bean>

            执行测试代码:

            结果如下:

            调用name的set方法

            调用age的set方法

            执行setEmail方法

            Student{name='张三', age=20}

            打印结果可见, setEmail方法也会调用, 所以<property>标签只是执行set方法, 不管你有没有这个属性

        引用类型的set注入

        Student.java信息如下:

        public class Student {
            private String name;
            private int age;

            // 声明一个引用类型
            private School school;

            public void setName(String name) {
            System.out.println("调用name的set方法");
                this.name = name;
            }

            public void setAge(int age) {
                System.out.println("调用age的set方法");
                this.age = age;
            }

            public void setSchool(School school) {
                this.school = school;
            }

            @Override
            public String toString() {
                return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", school=" + school +
                    '}';
            }
        }

        School.java信息如下:

        public class School {
            private String name;
            private String address;

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

            public void setAddress(String address) {
                this.address = address;
            }

        }

        applicationContext.xml文件如下:

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


        <!--    声明student对象-->
        <!--
            di : 给属性赋值
            简单类型 : spring中规定基本数据类型和String都是简单类型
            1. set注入(注入就是设值) : spring调用类的set方法, 可以在set方法中完成属性赋值
            引用类型的set注入
            <bean id="xx" class="yyy">
                <property name="属性的名字" ref="bean的id(对象的名称)" />
            </bean>
        -->

            <bean id="myStudent" class="org.example.ba02.Student">
            <property name="name" value="张三"/>
            <property name="age" value="20"/>
            <property name="school" ref="mySchool"/>
            <!--注意这里的mySchool在下面, spring扫描文件如果没有找到, 会再次扫描, 
            这里的顺序并不影响-->
            </bean>

            <!--    声明School类型的对象-->
            <bean id="mySchool" class="org.example.ba02.School" >
            <property name="name" value="北大"/>
            <property name="address" value="北京"/>
            </bean>

        </beans>

        测试代码如下:

        public class MyTest {

            @Test
            public void test01() {
                String config = "ba02/applicationContext.xml";
                ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                // 从容器中获取myStudent对象
                Student myStudent = (Student) ac.getBean("myStudent");
                System.out.println(myStudent);
            }
        }

        打印结果为:

        调用name的set方法

        调用age的set方法

        Student{name='张三', age=20, school=org.example.ba02.School@1b26f7b2}


构造注入 : 在构造实例的同时, 完成对象的实例化

    给出代码例子:
    Student.java如下:

    public class Student {
        private String name;
        private int age;

        // 声明一个引用类型
        private School school;

        public Student() {
            System.out.println("这是无参构造");
        }

        public Student(String name, int age, School school) {
            System.out.println("这是有参构造");
            this.name = name;
            this.age = age;
            this.school = school;
        }

        @Override
        public String toString() {
            return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
        }
    }

    School.java如下:

    public class School {
        private String name;
        private String address;

        public School(String name, String address) {
            this.name = name;
            this.address = address;
        }

        @Override
        public String toString() {
            return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
        }
    }

    applicationContext.xml文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--    声明student对象-->
    <!--
        di : 给属性赋值
        简单类型 : spring中规定基本数据类型和String都是简单类型
        构造注入 :
        使用 <constructor-arg> 标签
        一个 <constructor-arg> 标签表示构造方法的一个参数
        <constructor-arg> 标签属性 :
            name : 表示构造方法的形参名
            index : 表示构造方法的参数位置, 从左往右从0开始
            value : 如果构造方法的形参类型是简单类型, 使用value属性为其赋值
            ref : 构造方法的形参的参数如果是引用类型, 使用ref属性为其赋值

    -->
        <!--使用属性name-->
        <bean id="myStudent" class="org.example.ba03.Student" >
            <constructor-arg name="age" value="20"/>
            <constructor-arg name="name" value="张三"/>
            <constructor-arg name="school" ref="mySchool"/>
        </bean>

        <!--使用属性index-->
        <bean id="myStudent1" class="org.example.ba03.Student">
            <constructor-arg index="0" value="李四"/>
            <constructor-arg index="1" value="21"/>
            <constructor-arg index="2" ref="mySchool"/>
        </bean>

        <!--省略属性index-->
        <bean id="myStudent2" class="org.example.ba03.Student">
            <constructor-arg value="王五"/>
            <constructor-arg value="21"/>
            <constructor-arg ref="mySchool"/>
        </bean>

        <bean id="mySchool" class="org.example.ba03.School">
            <constructor-arg name="name" value="北京大学"/>
            <constructor-arg name="address" value="北京"/>
        </bean>

    </beans>

    测试代码如下:

    public class MyTest {

        @Test
        public void test01() {
            String config = "ba03/applicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(config);

            // 从容器中获取myStudent对象
            Student myStudent = (Student) ac.getBean("myStudent");
            System.out.println(myStudent);

            // 从容器中获取myStudent1对象
            Student myStudent1 = (Student) ac.getBean("myStudent1");
            System.out.println(myStudent1);

            // 从容器中获取myStudent2对象
            Student myStudent2 = (Student) ac.getBean("myStudent2");
            System.out.println(myStudent2);
        }

    }

    控制台打印结果如下:

    这是有参构造

    这是有参构造

    这是有参构造

    Student{name='张三', age=20, school=School{name='北京大学', address='北京'}}

    Student{name='李四', age=21, school=School{name='北京大学', address='北京'}}

    Student{name='王五', age=21, school=School{name='北京大学', address='北京'}}

配置文件方式总结 

    di : 给属性赋值

    简单类型 : spring中规定基本数据类型和String都是简单类型

        1. set注入(注入就是设值)

        spring调用类的set方法(没有set方法会运行时异常), 可以在set方法中完成属性赋值

        简单类型的set注入

            <bean id="xx" class="yyyy">
                一个property只能给一个属性赋值
                <property name="属性的名字" value="属性的值" />
            </bean>

        引用类型的set注入

            <bean id="xx" class="yyy">
                <property name="属性的名字" ref="bean的id(对象的名称)" />
            </bean>

        问题 : 如果没有属性, 但是有set方法, spring可以执行吗?  

            答案是可以

               两个bean标签有依赖关系, 那么他们在配置文件中的先后顺序有影响吗

            答案是没有影响, 因为如果第一遍没有找到对应的对象, 那么spring会浏览配置文件第二遍

        2. 构造注入 : 调用有参数的构造方法

        使用 <constructor-arg> 标签

        一个 <constructor-arg> 标签表示构造方法的一个参数

        <constructor-arg> 标签属性 :

            name : 表示构造方法的形参名

            index : 表示构造方法的参数位置, 从左往右从0开始

            value : 如果构造方法的形参类型是简单类型, 使用value属性为其赋值

            ref : 构造方法的形参的参数如果是引用类型, 使用ref属性为其赋值

引用类型的自动注入

    引用类型的自动注入

    spring框架根据某些规则可以自动给引用类型赋值, 简化程序员工作

    常用的规则为byName 和 byType

    1. byName(按名称注入)

        java类中的引用类型的属性名和spring配置文件<bean>的id相同时

                          且数据类型一样, 这样容器中的bean可以由spring自动赋值

       语法

        <bean id="xxx" class="yyy" autowire="byName">
            简单类型数据赋值
        </bean>

    2. byType(按类型注入) 

        java类中引用类型的数据类型和spring配置文件<bean>的class属性

                          是同源关系, 这样的bean能够赋值给引用类型

       同源的意思是:

       1. java类中引用类型和spring配置文件bean的class属性一样

       2. java类中引用类型和spring配置文件bean的class属性是父子关系, java类为父类, class是子类

       3. java类中引用类型和spring配置文件bean的class属性是接口和实现类关系

       语法:

        <bean id="xxx" class="yyy" autowire="byType">
            简单类型数据赋值
        </bean>

        注意, 在byType中, 需要自动注入的属性对象在容器中只能有一个, 要不然不会自动注入

        因为spring不知道你要注入的结果是哪一个

    测试byName

    语法如下:

        <!--测试byName-->
        <bean id="school" class="org.example.ba04.School" >
            <property name="name" value="北大"/>
            <property name="address" value="北京"/>
        </bean>

        <bean id="myStudent" class="org.example.ba04.Student" autowire="byName">
            <property name="name" value="张三"/>
            <property name="age" value="20"/>
        </bean>

    测试byType

    语法如下:

        <!--测试byType-->
        <bean id="mySchool" class="org.example.ba04.School" >
            <property name="name" value="清华"/>
            <property name="address" value="北京"/>
        </bean>

        <!--如果需要注入的类型, 在实例中有多个对象, 无法自动连线. “school”类型的bean不止一个.-->
        <bean id="myStudent" class="org.example.ba04.Student" autowire="byType">
            <property name="name" value="张三"/>
            <property name="age" value="20"/>
        </bean>


 

上一篇:Angular依赖注入笔记


下一篇:代写python assignment经常用到的代码语法分享!