Java教程

阶段二:SpringIOC控制反转

本文主要是介绍阶段二: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的目的:减少对代码的改动,也能实现不同功能。实现解耦合

Spring IoC 容器

IoC容器:

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

容器 & 描述
1Spring BeanFactory 容器

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

2Spring 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>

 第二步:创建一个接口

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

package org.example;

public interface SomeService {
    void doSome();
}

第三步:创建接口实现类

实现接口中声明的方法:

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方法!");
    }
}

第四步:在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 类似
-->

第五步:创建测试类

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);
    }
}

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

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

DI的语法分类:

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

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

2Setter-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;
    }
}

第二步:第二步:在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>

第三步:编写测试类

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);

    }
}

构造注入:

        当容器调用带有一组参数的类构造函数时,基于构造函数的 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 +
                '}';
    }
}
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 +
                '}';
    }
}

第二步:在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>

第三步:编写测试类

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);
    }
}

注入内部 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>

        内部 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();
    }
}
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;
    }
}

第二步:在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>

第三步:编写测试类

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();
    }
}

注入集合:

        传递多个值,如 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;
   }
}

第二步:在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>

第三步:创建测试类

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();
   }
}

注入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>

注入 null 和空字符串的值:

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

自动注入:

        自动装配就是指 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 +
                '}';
    }
}
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;
    }
}

第二步:在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>

第三步:创建测试类

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);
    }
}

ByType:

        这种模式由属性类型指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 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();
   }
}
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   }   
}

第二步:在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>

第三步:创建测试类

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();
   }
}

由构造函数自动装配

        这种模式与 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>

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 +
                '}';
    }
}

第二步:在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>

第三步:创建测试类

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);
    }
}

扫描多个包:

<!--指定多个包扫描的三种方式-->
<!--第一种方式:使用多次扫描组件,指定不同的包-->
<context:component-scan base-package="包路径1"/>
<context:component-scan base-package="包路径2"/>

<!--第二种方式:使用分隔符(;或者,)分隔多个包-->
<context:component-scan base-package="包路径1;包路径2"/>

<!--第三种方式:指定父包-->
<context:component-sacn base-package="父包"/>

引用类型注入:

第一步:创建实体类

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 + '\'' +
                '}';
    }
}
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 +
                '}';
    }
}

第二步: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>

properties配置文件

name=Tom
age=190

第三步:编写测试类

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);
    }
}

这篇关于阶段二:SpringIOC控制反转的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!