【Spring】SpringIOC控制反转

简介: 【1月更文挑战第20天】【Spring】SpringIOC控制反转

 目录

Spring核心功能IoC:

概述:

什么是控制反转:

IoC容器:

IOC的技术实现 :  

Spring的第一个程序:

第一步:创建一个Maven工程

第二步:创建一个接口

第三步:创建接口实现类

第四步:在resource资源文件目录下创建application.xml文件

第五步:创建测试类

基于XML文件的DI依赖注入:

DI的语法分类:

setter设值注入:

构造注入:

注入内部 Beans:

注入集合:

自动注入:

自动装配模式:

自动装配的局限性:

ByName:

ByType:

由构造函数自动装配

基于注解的配置:

对象创建及基本属性注入:

扫描多个包:

引用类型注入:


Spring核心功能IoC:

概述:

       IOC(Inversion of Control):控制反转,是一种理论,概念,思想。把对象的创建,赋值,管理工作交给代码之外的容器实现,也就是对象的创建是由其他的外部资源完成。

什么是控制反转:

    • 控制:创建对象,对象的属性赋值,对象之间的关系管理。
    • 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象,创建对象。
    • 正转:由开发人员在代码中实现,使用new构造方法创建对象,开发人员主动管理对象。
    • 容器:一个服务器软件,一个框架(spring)

           Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件,这些对象被称为 Spring Beans。

           通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

           IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。

    Java中创建对象的方式:

      • 构造方法
      • 反射
        • 克隆
        • 序列化
          • ioc创建对象
          • 动态代理

                 使用IoC的目的:减少对代码的改动,也能实现不同功能。实现解耦合

          image.gif编辑

          IoC容器:

          Spring 提供了以下两种不同类型的容器:

          容器 & 描述
          1 Spring BeanFactory 容器

          它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。

          2 Spring ApplicationContext 容器

          该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

                 ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。


          IOC的技术实现 :  

          DI 是ioc的技术实现。

          DI(Dependency Injection):依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,赋值,查找都由容器内部实现。

          spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。

          spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。

          spring-conetxt spring-webmvc 是spring中的两个模块

          spring-context:是ioc功能的,创建对象的。

          spring-webmvc做web开发使用的, 是servlet的升级。  

          spring-webmvc中也会用到spring-context中创建对象的功能的。


          Spring的第一个程序:

          第一步:创建一个Maven工程

          导入Spring和junit依赖到pom.xml中:

          <!--junit单元测试依赖-->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.11</version>
              <scope>test</scope>
          </dependency>
          <!--Spring依赖-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.3.9</version>
          </dependency>

          image.gif

          第二步:创建一个接口

                 创建一个接口类,在通常业务中,我们通常使用接口来声明方法,通过接口实现类来完成方法,业务逻辑的具体实现!

          package org.example;
          public interface SomeService {
              void doSome();
          }

          image.gif

          第三步:创建接口实现类

          实现接口中声明的方法:

          package org.example.imp;
          import org.example.SomeService;
          public class SomeServiceImpl implements SomeService {
              //空参构造器:spring默认调用:
              public SomeServiceImpl() {
                  System.out.println("spring调用了SomeServiceImpl的空参构造器!");
              }
              @Override
              public void doSome() {
                  System.out.println("执行了SomeServiceImp的doSome方法!");
              }
          }

          image.gif

          第四步:在resource资源文件目录下创建application.xml文件

          把创建好的实现类交给Spring容器进行管理:

          <?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">
          <!--    约束文件路径——xml文件-->
          <!--
                  告诉spring创建对象
                  声明bean,就是告诉spring要创建某个类的对象
                  id:对象的自定义名称,唯一值。spring通过这个名称找到对象
                  class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)
          -->
              <bean id="someService" class="org.example.imp.SomeServiceImpl" />
              <bean id="someService1" class="org.example.imp.SomeServiceImpl" />
          <!--    spring底层完成:SomeService someService = new SomeServiceImp();
                  spring把创建好的对象放入map中,spring框架有一个map存放对象
                      springMap.put(id值,对象);
                  一个bean标签声明一个Java对象。
          -->
          <!--
                  spring能创建一个非自定义类的对象,创建一个存在的某个类的对象。
          -->
              <bean id="mydate" class="java.util.Date"/>
          </beans>
          <!--
              spring的配置文件
              1.beans:根标签,spring把Java对象称为bean
              2.spring-beans.xsd 是约束文件,和mybatis指定 dtd 类似
          -->

          image.gif

          第五步:创建测试类

          package org.example;
          import org.junit.Test;
          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;
          import java.util.Date;
          public class MyTest {
              /*
              spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中所有的对象。
              spring创建对象:默认调用的是无参构造方法
               */
              @Test
              public void test01(){
                  //使用spring容器创建对象:
                  //1.指定spring配置文件名称
                  String config = "application.xml";
                  //2.创建表示spring容器的对象,ApplicationContext
                  //ApplicationContext就是表示spring容器,通过容器对象获取对象
                  ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                  //从容其中获取某个对象,调用对象方法
                  //getBean("配置文件中bean的id值")
                  SomeService service = (SomeService) ac.getBean("someService");
                  //使用spring创建好的对象,调用方法:
                  service.doSome();
              }
              /**
               * 获取spring容器中Java对象信息
               */
              @Test
              public void test02(){
                  String config = "application.xml";
                  ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                  //使用spring提供的方法,获取容器中定义的对象数量
                  int num = ac.getBeanDefinitionCount();
                  System.out.println("容器中所含对象数量:" + num);
                  //容器中每个定义对象的名称
                  String[] names = ac.getBeanDefinitionNames();
                  //增强for循环:
                  for (String name : names){
                      System.out.println(name);
                  }
              }
              /**
               * 获取一个非自定义类的对象
               */
              @Test
              public void test03(){
                  String config = "application.xml";
                  ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                  //使用getBean();获取对象
                  Date md = (Date) ac.getBean("mydate");
                  System.out.println("系统时间:" + md);
              }
          }

          image.gif


          基于XML文件的DI依赖注入:

                 Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。在spring的XML配置文件中,给java对象的属性赋值。DI注入:创建对象,给属性赋值。

          DI的语法分类:

          依赖注入类型 & 描述
          1 Constructor-based dependency injection(构造器方法注入)

          当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系。

          2 Setter-based dependency injection(setter方法注入)

          基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。

            • set注入(设置注入):Spring调用类的set方法,在set方法中实现属性的赋值。
            • 构造注入:Spring调用类的有参构造方法,创建对象,在构造方法中完成赋值。

            setter设值注入:

                   当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。

            第一步:创建一个实体类

            package org.example.ba01;
            public class Student {
                String name;
                int age;
                public Student() {
                }
                public Student(String name, int age) {
                    this.name = name;
                    this.age = age;
                }
                @Override
                public String toString() {
                    return "Student{" +
                            "name='" + name + '\'' +
                            ", age=" + age +
                            '}';
                }
                public void setName(String name) {
                    this.name = name;
                }
                public void setAge(int age) {
                    this.age = age;
                }
            }

            image.gif

            第二步:第二步:在resource目录下编写application.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规定在Java的基本数据类型和String都是简单类型。
                1.set注入(设置注入):spring调用类的set方法,你可以在set方法中完成属性赋值
                    1)简单类型注入
                        <bean id="XXX" class="YYY">
                            <property name="属性名字" value="此属性的值" />
                            一个property只能给一个属性赋值
                            <property ... >
                        </bean>
                    2) 引用类型的注入:spring调用类的set方法
                    <bean id="XXX" class="YYY">
                        <property name="属性名称" ref="bean的id(对象名称)"/>
                    </bean>
            -->
                <bean id="mystudent" class="org.example.ba01.Student">
                    <property name="name" value="TOM"/>
                    <property name="age" value="19"/>
                </bean>
            </beans>

            image.gif

            第三步:编写测试类

            package org.example;
            import org.example.ba01.Student;
            import org.junit.Test;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MyTest {
                @Test
                public void test01(){
                    //定义配置文件路径:
                    String config = "application.xml";
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //从容器中获得student
                    Student myStudent = (Student) ac.getBean("mystudent");
                    System.out.println("studnet对象:" + myStudent);
                }
            }

            image.gif

            构造注入:

                   当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。

            第一步:创建实体类

            package org.example.ba01;
            public class School {
                String name;
                int number;
                public School(String name, int number) {
                    this.name = name;
                    this.number = number;
                }
                public School(){
                }
                @Override
                public String toString() {
                    return "School{" +
                            "name='" + name + '\'' +
                            ", number=" + number +
                            '}';
                }
            }

            image.gif

            package org.example.ba01;
            public class Student {
                String name;
                int age;
                //声明一个引用类型
                School school;
                public Student(){
                }
                //创建有参构造方法:
                public Student(String name, int age,School school) {
                    System.out.println("Student有参构造方法,给属性赋值!");
                    this.name = name;
                    this.age = age;
                    this.school = school;
                }
                @Override
                public String toString() {
                    return "Student{" +
                            "name='" + name + '\'' +
                            ", age=" + age +
                            ", school=" + school +
                            '}';
                }
            }

            image.gif

            第二步:在resource目录下编写application.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">
            <!--
                    2.构造注入:spring调用类的有参构造方法,在创建对象的同时,在构造方法中给属性赋值。
                        构造注入使用 <constructor-arg>标签
                        <constructor-arg>标签:一个<constructor-arg>表示构造方法一个参数。
                        <constructor-arg>标签属性:
                            name:表示构造方法名
                            index:表示构造方法的参数位置,参数从左往右位置是 0,1,2...的顺序
                            value:构造方法的形参类型是简单类型使用,value
                            ref:构造方法的形参类型是引用类型的,使用ref
            -->
            <!--    声明School对象-->
                <bean id="mySchool" class="org.example.ba01.School">
                    <constructor-arg name="name" value="大学"/>
                    <constructor-arg name="number" value="100"/>
                </bean>
            <!--    声明Student对象-->
                <bean id="myStudent" class="org.example.ba01.Student">
            <!--        <constructor-arg name="name" value="Tom"/>-->
            <!--        <constructor-arg name="age" value="19"/>-->
            <!--        <constructor-arg name="school" ref="mySchool"/>-->
            <!--        使用:index属性,进行赋值:-->
                    <constructor-arg index="0" value="Hurry"/>
                    <constructor-arg index="1" value="19"/>
                    <constructor-arg index="2" ref="mySchool"/>
            <!--        index属性可以省略,省略后注意赋值顺序和构造函数的排序一致!-->
                </bean>
            </beans>

            image.gif

            第三步:编写测试类

            package org.example;
            import org.example.ba01.Student;
            import org.junit.Test;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MyTest {
                @Test
                public void test(){
                    //1.创建配置文件路径:
                    String config = "application.xml";
                    //2.创建容器:
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //3.从容器中获取对象:
                    Student myStudent = (Student) ac.getBean("myStudent");
                    //4.通过对象调用方法:
                    System.out.println("Student : " + myStudent);
                }
            }

            image.gif

            注入内部 Beans:

                   Java 内部类是在其他类的范围内被定义的,同理,inner beans 是在其他 bean 的范围内定义的 bean。因此<property />或<constructor-arg />元素中的<bean />元素称为内部bean。

            <?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-3.0.xsd">
               <bean id="outerBean" class="...">
                  <property name="target">
                     <bean id="innerBean" class="..."/>
                  </property>
               </bean>
            </beans>

            image.gif

                   内部 Bean 的定义不需要指定 id 和 name 。如果指定了,容器也不会将其作为区分 Bean 的标识符,反而会无视内部 Bean 的 scope 属性。所以内部 Bean 总是匿名的,而且总是随着外部 Bean 创建。

            第一步:创建实体类

            public class Person {
                private Man man;
                public Man getMan() {
                    return man;
                }
                public void setMan(Man man) {
                    System.out.println("在setMan方法内");
                    this.man = man;
                }
                public void man() {
                    man.show();
                }
            }

            image.gif

            public class Man {
                private String name;
                private int age;
                public Man() {
                    System.out.println("在man的构造函数内");
                }
                public Man(String name, int age) {
                    System.out.println("在man的有参构造函数内");
                    this.name = name;
                    this.age = age;
                }
                public void show() {
                    System.out.println("名称:" + name + "\n年龄:" + age);
                }
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
                public int getAge() {
                    return age;
                }
                public void setAge(int age) {
                    this.age = age;
                }
            }

            image.gif

            第二步:在resource目录下编写application.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-3.0.xsd">
                <bean id="person" class="net.biancheng.Person">
                    <property name="man">
                        <bean class="net.biancheng.Man">
                            <property name="name" value="bianchengbang" />
                            <property name="age" value="12" />
                        </bean>
                    </property>
                </bean>
            </beans>

            image.gif

            第三步:编写测试类

            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MainApp {
                public static void main(String[] args) {
                    ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
                    Person person = (Person) context.getBean("person");
                    person.man();
                }
            }

            image.gif

            注入集合:

                   传递多个值,如 Java Collection 类型 List、Set、Map 和 Properties,应该怎么做呢。为了处理这种情况,Spring 提供了四种类型的集合的配置元素,如下所示:

            标签 说明
            <list> 用于注入 list 类型的值,允许重复
            <set> 用于注入 set 类型的值,不允许重复
            <map> 用于注入 key-value 的集合,其中 key-value 可以是任意类型
            <props> 用于注入 key-value 的集合,其中 key-value 都是字符串类型

            可以使用<list><set>来连接任何 java.util.Collection 的实现或数组。

            第一步:创建实体类

            import java.util.*;
            public class JavaCollection {
               List addressList;
               Set  addressSet;
               Map  addressMap;
               Properties addressProp;
               // a setter method to set List
               public void setAddressList(List addressList) {
                  this.addressList = addressList;
               }
               // prints and returns all the elements of the list.
               public List getAddressList() {
                  System.out.println("List Elements :"  + addressList);
                  return addressList;
               }
               // a setter method to set Set
               public void setAddressSet(Set addressSet) {
                  this.addressSet = addressSet;
               }
               // prints and returns all the elements of the Set.
               public Set getAddressSet() {
                  System.out.println("Set Elements :"  + addressSet);
                  return addressSet;
               }
               // a setter method to set Map
               public void setAddressMap(Map addressMap) {
                  this.addressMap = addressMap;
               }  
               // prints and returns all the elements of the Map.
               public Map getAddressMap() {
                  System.out.println("Map Elements :"  + addressMap);
                  return addressMap;
               }
               // a setter method to set Property
               public void setAddressProp(Properties addressProp) {
                  this.addressProp = addressProp;
               } 
               // prints and returns all the elements of the Property.
               public Properties getAddressProp() {
                  System.out.println("Property Elements :"  + addressProp);
                  return addressProp;
               }
            }

            image.gif

            第二步:在resource目录下编写application.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-3.0.xsd">
               <!-- Definition for javaCollection -->
               <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
                  <!-- results in a setAddressList(java.util.List) call -->
                  <property name="addressList">
                     <list>
                        <value>INDIA</value>
                        <value>Pakistan</value>
                        <value>USA</value>
                        <value>USA</value>
                     </list>
                  </property>
                  <!-- results in a setAddressSet(java.util.Set) call -->
                  <property name="addressSet">
                     <set>
                        <value>INDIA</value>
                        <value>Pakistan</value>
                        <value>USA</value>
                        <value>USA</value>
                    </set>
                  </property>
                  <!-- results in a setAddressMap(java.util.Map) call -->
                  <property name="addressMap">
                     <map>
                        <entry key="1" value="INDIA"/>
                        <entry key="2" value="Pakistan"/>
                        <entry key="3" value="USA"/>
                        <entry key="4" value="USA"/>
                     </map>
                  </property>
                  <!-- results in a setAddressProp(java.util.Properties) call -->
                  <property name="addressProp">
                     <props>
                        <prop key="one">INDIA</prop>
                        <prop key="two">Pakistan</prop>
                        <prop key="three">USA</prop>
                        <prop key="four">USA</prop>
                     </props>
                  </property>
               </bean>
            </beans>

            image.gif

            第三步:创建测试类

            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MainApp {
               public static void main(String[] args) {
                  ApplicationContext context = 
                         new ClassPathXmlApplicationContext("application.xml");
                  JavaCollection jc=(JavaCollection)context.getBean("javaCollection");
                  jc.getAddressList();
                  jc.getAddressSet();
                  jc.getAddressMap();
                  jc.getAddressProp();
               }
            }

            image.gif

            注入Bean引用:

            <?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-3.0.xsd">
               <!-- Bean Definition to handle references and values -->
               <bean id="..." class="...">
                  <!-- Passing bean reference  for java.util.List -->
                  <property name="addressList">
                     <list>
                        <ref bean="address1"/>
                        <ref bean="address2"/>
                        <value>Pakistan</value>
                     </list>
                  </property>
                  <!-- Passing bean reference  for java.util.Set -->
                  <property name="addressSet">
                     <set>
                        <ref bean="address1"/>
                        <ref bean="address2"/>
                        <value>Pakistan</value>
                     </set>
                  </property>
                  <!-- Passing bean reference  for java.util.Map -->
                  <property name="addressMap">
                     <map>
                        <entry key="one" value="INDIA"/>
                        <entry key ="two" value-ref="address1"/>
                        <entry key ="three" value-ref="address2"/>
                     </map>
                  </property>
               </bean>
            </beans>

            image.gif

            注入 null 和空字符串的值:

            <bean id="..." class="exampleBean">
               <property name="email" value=""/>
            </bean>

            image.gif

            <bean id="..." class="exampleBean">
               <property name="email"><null/></property>
            </bean>

            image.gif


            自动注入:

                   自动装配就是指 Spring 容器在不使用 <constructor-arg> 和<property> 标签的情况下,可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。

            自动装配模式:

                   下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用<bean>元素的 autowire 属性为一个 bean 定义指定自动装配模式。

            名称 说明
            no 默认值,表示不使用自动装配,Bean 依赖必须通过 ref 元素定义。
            byName 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。
            byType 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。
            constructor 类似于 byType,根据构造方法参数的数据类型,进行 byType 模式的自动装配。
            autodetect(3.0版本不支持) 如果 Bean 中有默认的构造方法,则用 constructor 模式,否则用 byType 模式。

            可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。

            自动装配的局限性:

                   当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。

            限制 描述
            重写的可能性 你可以使用总是重写自动装配的 <constructor-arg>和 <property> 设置来指定依赖关系。
            原始数据类型 你不能自动装配所谓的简单类型包括基本类型,字符串和类。
            混乱的本质

            自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配。

            ByName:

            第一步:创建实体类

            package org.example.ba02;
            public class School {
                String name;
                int number;
                public School(String name, int number) {
                    this.name = name;
                    this.number = number;
                }
                public School(){
                }
                @Override
                public String toString() {
                    return "School{" +
                            "name='" + name + '\'' +
                            ", number=" + number +
                            '}';
                }
            }

            image.gif

            package org.example.ba02;
            public class Student {
                String name;
                int age;
                //声明一个引用类型
                School school = null;//要和配置文件中School类的<bean>的id值相同
                @Override
                public String toString() {
                    return "Student{" +
                            "name='" + name + '\'' +
                            ", age=" + age +
                            ", 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;
                }
            }

            image.gif

            第二步:在resource目录下编写application.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">
            <!--
                    引用类型的自动注入: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类中引用类型的数据类型和bean的class的值是一样的。
                  2.Java类中引用类型的数据类型和bean的class的值是父子类关系的。
                  3.Java类中引用类型的数据类型和bean的class的值接口和实现类关系的。
                  语法:
                  <bean id="XXX" class="YYY" autowire="byType">
                    简单类型属性赋值
                  </bean>
            -->
            <!--    声明School对象-->
                <bean id="school" class="org.example.ba02.School">  <!--id值要和Student类的School属性名一致-->
                    <constructor-arg name="name" value="大学"/>
                    <constructor-arg name="number" value="100"/>
                </bean>
            <!--    声明Student对象         byName自动注入-->
                <bean id="myStudent" class="org.example.ba02.Student" autowire="byName">
                    <property name="name" value="AJX"/>
                    <property name="age" value="19"/>
                </bean>
            <!--    声明Student对象         byType自动注入-->
                <bean id="myStudent01" class="org.example.ba02.Student" autowire="byType">
                    <property name="name" value="Kay" />
                    <property name="age" value="20"/>
                </bean>
            </beans>

            image.gif

            第三步:创建测试类

            package org.example;
            import org.example.ba02.Student;
            import org.junit.Test;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MyTest01 {
                @Test
                public void test01(){
                    //1.创建配置文件路径:
                    String config = "application.xml";
                    //2.创建容器对象:
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //3.通过容器获取对象:
                    Student myStudent = (Student) ac.getBean("myStudent");
                    //4.通过对象调用方法:
                    System.out.println("Student :" + myStudent);
                }
                @Test
                public void test02(){
                    //1.创建配置文件路径:
                    String config = "application.xml";
                    //2.创建容器对象:
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //3.通过容器获取对象:
                    Student myStudent = (Student) ac.getBean("myStudent01");
                    //4.通过对象调用方法:
                    System.out.println("Student :" + myStudent);
                }
            }

            image.gif

            ByType:

                   这种模式由属性类型指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beansautowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

            第一步:创建实体类

            public class TextEditor {
               private SpellChecker spellChecker;
               private String name;
               public void setSpellChecker( SpellChecker spellChecker ) {
                  this.spellChecker = spellChecker;
               }
               public SpellChecker getSpellChecker() {
                  return spellChecker;
               }
               public void setName(String name) {
                  this.name = name;
               }
               public String getName() {
                  return name;
               }
               public void spellCheck() {
                  spellChecker.checkSpelling();
               }
            }

            image.gif

            public class SpellChecker {
               public SpellChecker(){
                  System.out.println("Inside SpellChecker constructor." );
               }
               public void checkSpelling() {
                  System.out.println("Inside checkSpelling." );
               }   
            }

            image.gif

            第二步:在resource目录下编写application.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-3.0.xsd">
               <!-- Definition for textEditor bean -->
               <bean id="textEditor" class="com.tutorialspoint.TextEditor" 
                  autowire="byType">
                  <property name="name" value="Generic Text Editor" />
               </bean>
               <!-- Definition for spellChecker bean -->
               <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">
               </bean>
            </beans>

            image.gif

            第三步:创建测试类

            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MainApp {
               public static void main(String[] args) {
                  ApplicationContext context = 
                         new ClassPathXmlApplicationContext("application.xml");
                  TextEditor te = (TextEditor) context.getBean("textEditor");
                  te.spellCheck();
               }
            }

            image.gif

            由构造函数自动装配

                   这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。


            基于注解的配置:

                   通过spring的注解完成Java对象的创建,属性的赋值。代替xml文件

                   从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

                   在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。

                   注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。

            <?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-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd">
               <context:annotation-config base-package="包路径"/>
               <!-- bean definitions go here -->
            </beans>

            image.gif

            1)@Component

                   可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。

            2)@Repository

                   用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

            3)@Service

                   通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

            4)@Controller

                   通常作用在控制层(如 Struts2 的 Action、SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

            5)@Autowired

                   可以应用到 Bean 的属性变量、属性的 setter 方法、非 setter 方法及构造函数等,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

            6)@Resource

                   作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。


            @Resource 中有两个重要属性:name 和 type。


                   Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

            7)@Qualifier

                   与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。

            对象创建及基本属性注入:

            第一步:创建实体类

            package org.example;
            import org.springframework.stereotype.Component;
            /**
             * @Component: 创建对象的,等同于<bean>的功能
             *  属性:value 就是对象的名称,也就是bean的id值
             *       value的值是唯一的,创建的对象在整个spring容器中就一个
             *  位置:在类的上面
             *
             * @Component(value = "myStudent")等同于 <bean id="myStudent" class="org.example.Student" />
             *
             * spring中和@component 功能一致,创建对对象的注解还有:
             * 1、@Repository(用在持久层类的上面):放在dao的实现类的上面,表示创建dao对象,dao对象是能访问数据库的。
             * 2、@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务功能的。
             * 3、@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的
             *
             * 以上三个注解使用语法和@Component一致。都能创建对象,但是这三个注释还有额外的功能
             *
             * @Repository,@Service,@Controller是给项目对象分层的。
             */
            //省略value
            //@Component("myStudent")
            //不指定对象名称,由spring默认提供,value值为:类名首字母小写
            //@Component
            //显示的使用value属性
            @Component(value = "myStudent")
            public class Student {
                String name;
                int age;
                public Student(){
                }
                public Student(String name, int age) {
                    this.name = name;
                    this.age = age;
                }
                public void setName(String name) {
                    this.name = name;
                }
                public void setAge(int age) {
                    this.age = age;
                }
                @Override
                public String toString() {
                    return "Student{" +
                            "name='" + name + '\'' +
                            ", age=" + age +
                            '}';
                }
            }

            image.gif

            第二步:在resource目录下编写application.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"
                   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">
            <!--
                    声明组件扫描器(component-scan)
                    组件:Java对象
                    base-package:指定注解在你的项目中的包名
                    component-scan工作方式:spring会扫描遍历base-package指定的包,把包中的所有类,
                                           找到类中的注解,按照注解功能创建对象,给属性赋值
                    加入component-scan标签,配置文件的变化:
                    http://www.springframework.org/schema/context ——命名空间
                    https://www.springframework.org/schema/context/spring-context.xsd ——url
                    1.加入一个新的约束文件spring-context.xsd
                    2.给这个新的约束文件起个命名空间的名称
            -->
                <context:component-scan base-package="org.example"/>
            </beans>

            image.gif

            第三步:创建测试类

            package org.example;
            import org.junit.Test;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MyTest {
                @Test
                public void test01(){
                    //1.创建配置文件路径:
                    String config = "applicationContext.xml";
                    //2.创建容器:
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //3.通过容器获取对象:
                    Student myStudent = (Student) ac.getBean("myStudent");
                    //4.通过对象调用方法:
                    System.out.println("Student:" + myStudent);
                }
            }

            image.gif

            扫描多个包:

            <!--指定多个包扫描的三种方式-->
            <!--第一种方式:使用多次扫描组件,指定不同的包-->
            <context:component-scan base-package="包路径1"/>
            <context:component-scan base-package="包路径2"/>
            <!--第二种方式:使用分隔符(;或者,)分隔多个包-->
            <context:component-scan base-package="包路径1;包路径2"/>
            <!--第三种方式:指定父包-->
            <context:component-sacn base-package="父包"/>
            image.gif

            引用类型注入:

            第一步:创建实体类

            package org.example;
            import org.springframework.beans.factory.annotation.Value;
            import org.springframework.stereotype.Component;
            @Component("mySchool")
            public class School {
                @Value("重庆邮电大学")
                String name;
                @Value("南山之颠,黄河以北")
                String address;
                public School() {
                }
                public School(String name, String address) {
                    this.name = name;
                    this.address = address;
                }
                public void setName(String name) {
                    this.name = name;
                }
                public void setAddress(String address) {
                    this.address = address;
                }
                @Override
                public String toString() {
                    return "School{" +
                            "name='" + name + '\'' +
                            ", address='" + address + '\'' +
                            '}';
                }
            }

            image.gif

            package org.example;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.beans.factory.annotation.Qualifier;
            import org.springframework.beans.factory.annotation.Value;
            import org.springframework.stereotype.Component;
            @Component(value = "myStudent")
            public class Student {
                /**
                 * @Value: 简单类型的属性赋值
                 *  属性:value 是String类型的,表示简单类型的属性值
                 *  位置:1.在属性定义的上面,无需set方法 (推荐使用)
                 *       2.在set方法的上面
                 *
                 *
                 * @Valude: 引用类型的属性赋值
                 * @Autowired: spring框架提供注解,实现引用类型的赋值。
                 * spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
                 *
                 * @Autowired:默认使用byType自动注入
                 *
                 *  属性:
                 *        required ,是一个boolean类型的,默认true
                 *        required=true:表示引用类型赋值失败,程序报错,并终止执行。
                 *        required=false:表示引用类型赋值失败,程序正常执行,引用类型是null
                 *
                 *  位置:1.在属性定义的上面,无需set方法(推荐使用)
                 *        2.在set方法上面
                 *
                 * @Autowired:使用byName注入方式:
                 *  1.在属性上加@Autowired
                 *  2.在属性上加入@Quallifier(value="bean的id") :表示使用指定名称的bean完成对象创建
                 *
                 *
                 *  引用类型
                 * @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用他给引用类型属性赋值。
                 *             使用的也是自动类型注入原理,支持byName,byType,默认是byName
                 *
                 *  位置:1.在属性上方定义,无需set方法(推荐使用)
                 *        2.在set方法上
                 *
                 * @Resource:只是用byName方式,需要增加一个属性 name
                 * name的值是bean的id(名称)
                 */
                //默认是byName:先使用byName自定注入,如果byName赋值失效,再使用byType
            //    @Value(value = "Tom")  //value可以省
            //  使用资源文件赋值:
                        @Value("${name}")
                String name;
            //    @Value(value = "21")
                @Value("${age}")
                int age;
                //引用类型属性:
                @Autowired
                        @Qualifier(value = "mySchool")
                School school;
                public Student(){
                }
                public Student(String name, int age) {
                    this.name = name;
                    this.age = age;
                }
            //    @Value(value = "harry")
            //    public void setName(String name) {
            //        this.name = name;
            //    }
            //
            //    public void setAge(int age) {
            //        this.age = age;
            //    }
                @Override
                public String toString() {
                    return "Student{" +
                            "name='" + name + '\'' +
                            ", age=" + age +
                            ", school=" + school +
                            '}';
                }
            }

            image.gif

            第二步: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"
                   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">
            <!--
                    声明组件扫描器(component-scan)
                    组件:Java对象
                    base-package:指定注解在你的项目中的包名
                    component-scan工作方式:spring会扫描遍历base-package指定的包,把包中的所有类,
                                           找到类中的注解,按照注解功能创建对象,给属性赋值
                    加入component-scan标签,配置文件的变化:
                    http://www.springframework.org/schema/context ——命名空间
                    https://www.springframework.org/schema/context/spring-context.xsd ——url
                    1.加入一个新的约束文件spring-context.xsd
                    2.给这个新的约束文件起个命名空间的名称
            -->
                <context:component-scan base-package="org.example"/>
            <!--    声明资源文件路径-->
                <context:property-placeholder location="MyResource.properties"/>
            </beans>

            image.gif

            properties配置文件

            name=Tom
            age=190

            image.gif

            第三步:编写测试类

            package org.example;
            import org.junit.Test;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            public class MyTest {
                @Test
                public void test01(){
                    //1.创建配置文件路径:
                    String config = "applicationContext.xml";
                    //2.创建容器:
                    ApplicationContext ac = new ClassPathXmlApplicationContext(config);
                    //3.通过容器获取对象:
                    Student myStudent = (Student) ac.getBean("myStudent");
                    //4.通过对象调用方法:
                    System.out.println("Student:" + myStudent);
                }
            }

            image.gif


            相关文章
            |
            XML Java 数据格式
            03Spring - 控制反转IOC入门案例
            03Spring - 控制反转IOC入门案例
            48 0
            |
            7月前
            |
            XML Java 数据格式
            深入理解 Spring IoC 和 DI:掌握控制反转和依赖注入的精髓
            在本文中,我们将介绍 IoC(控制反转)和 DI(依赖注入)的概念,以及如何在 Spring 框架中实现它们。
            486 0
            |
            7月前
            |
            Java Spring
            Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
            Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
            |
            7月前
            |
            Java API Spring
            Spring6-IoC(Inversion of Control)控制反转和DI(Dependency Injection)依赖注入,手动实现IOC
            Spring6-IoC(Inversion of Control)控制反转和DI(Dependency Injection)依赖注入,手动实现IOC
            |
            Java 测试技术 Spring
            Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成(二)
            Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成
            |
            5月前
            |
            XML Java 测试技术
            Spring Boot中的依赖注入和控制反转
            Spring Boot中的依赖注入和控制反转
            |
            2月前
            |
            存储 Java 程序员
            SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
            本文详细讲解了Spring框架中IOC容器如何存储和取出Bean对象,包括五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)和方法注解@Bean的用法,以及DI(依赖注入)的三种注入方式:属性注入、构造方法注入和Setter注入,并分析了它们的优缺点。
            39 0
            SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
            |
            7月前
            |
            Java 测试技术 开发者
            Spring IoC容器通过依赖注入机制实现控制反转
            【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
            66 0
            |
            6月前
            |
            XML Java 测试技术
            Spring IOC 控制反转总结
            Spring IOC 控制反转总结
            |
            6月前
            |
            存储 Java 测试技术
            Java Spring IoC&DI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性
            Java Spring IoC&DI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性
            44 1