Spring02--IOC 控制反转

控制反转(IOC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。

IOC 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式是依赖注入。应用广泛。

依赖:classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完成功能,即 classA 对 classB 有依赖。

依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。

依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持对象之间依赖关系的管理。

Spring 框架使用依赖注入(DI)实现 IOC。

Spring 容器是一个大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。

1.1 Spring 的第一个程序

1.1.1 创建 maven 项目

在这里插入图片描述

1.1.2 引入 maven 依赖 pom.xml

<dependencies>
    <!--单元测试-->
    <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.2.5.RELEASE</version>
    </dependency>
  </dependencies>

  <!--插件-->
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

1.1.3 定义接口与实体类

SomeService接口:

package com.suyv.spring.service;

public interface SomeService {
    void doSome();
}

实现类:

package com.suyv.spring.service.Impl;

import com.suyv.spring.service.SomeService;

public class SomeServiceImpl implements SomeService {

    public SomeServiceImpl() {
        super();
        System.out.println("SomeServiceImpl无参数构造方法");
    }

    @Override
    public void doSome() {
        System.out.println("====业务方法doSome()===");
    }
}

1.1.4 创建 Spring 配置文件

spring 配置中需要加入约束文件才能正常使用,约束文件是 xsd 扩展名。

<?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">
	<!--<bean />:用于定义一个实例对象。一个实例对应一个 bean 元素。-->
	<!--id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。-->
	<!--class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。-->
    <bean id="someService" class="com.suyv.spring.service.Impl.SomeServiceImpl"></bean>
</beans>

1.1.5 定义测试类

	@Test
    public void test01(){
        //1.指定spring配置文件的名称
        String resource = "beans.xml";
        //2.创建表示spring容器的对象, ApplicationContext
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        //3.从容器中获取某个对象, 你要调用对象的方法
        SomeService service = (SomeService)ac.getBean("someService");
        //4.执行业务的对象方法
        service.doSome();
    }

执行结果:
在这里插入图片描述

1.1.6 使用 spring 创建非自定义类对象

spring 配置文件加入 java.util.Date 定义:

<bean id="myDate" class="java.util.Date" />

MyTest 测试类中:

	@Test
    public void test02(){
        String config = "beans.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        Date mydate = (Date) ac.getBean("mydate");
        System.out.println("Date" + mydate);
    }

执行结果:
在这里插入图片描述

1.1.7 容器接口和实现类

1)ApplicationContext 接口

ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现类有两个。
在这里插入图片描述

  • 配置文件在类路径下
    若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现类进行加载。
    在这里插入图片描述

  • ApplicationContext 容器中对象的装配时机
    ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。

1.2 基于 XML 的 DI

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类:set 注入、构造注入。

1.2.1 注入分类

1)set 注入

set 注入也叫设值注入,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。

A. 简单类型

实体类:

package com.suyv.spring.ba01;

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

    public void setName(String name) {
        System.out.println("学生姓名:"+name);
        this.name = name;
    }

    public void setAge(int age) {
        System.out.println("学生年龄:"+age);
        this.age = age;
    }

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

Spring配置文件:

    <bean id="myStudent" class="com.suyv.spring.ba01.Student">
        <property name="name" value="李四"></property>
        <property name="age" value="20"></property>
    </bean>

测试方法:

	@Test
    public void test01(){
        //指定spring配置文件的位置和名称
        String resource = "ba01/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

B. 引用类型

当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。ref 的值必须为某 bean 的 id 值。
实体类:

package com.suyv.spring.ba02;

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

    public void setName(String name) {
        System.out.println("学生姓名:"+name);
        this.name = name;
    }

    public void setAge(int age) {
        System.out.println("学生年龄:"+age);
        this.age = age;
    }

    public void setSchool(School school) {
        System.out.println("学生学校:"+school);
        this.school = school;
    }

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

package com.suyv.spring.ba02;

public class School {
    private String Name;
    private String Address;

    public void setName(String name) {
        Name = name;
    }

    public void setAddress(String address) {
        Address = address;
    }

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

Spring配置文件:

<bean id="myStudent" class="com.suyv.spring.ba02.Student">
        <property name="name" value="李四"></property>
        <property name="age" value="20"></property>
        <property name="school" ref="mySchool"></property>
    </bean>

    <bean id="mySchool" class="com.suyv.spring.ba02.School">
        <property name="name" value="河南科技大学"></property>
        <property name="address" value="河南省洛阳市"></property>
    </bean>

测试方法:

	@Test
    public void test02(){
        //指定spring配置文件的位置和名称
        String resource = "ba02/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

2)构造注入

构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。

实体类:Student类与School类
Spring配置文件:
在这里插入图片描述

A. 使用name属性

Spring配置文件:
在这里插入图片描述
测试方法:

@Test
    public void test031(){
        //指定spring配置文件的位置和名称
        String resource = "ba03/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent01");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

B. 使用index属性

Spring配置文件:
在这里插入图片描述

测试方法:

@Test
    public void test032(){
        //指定spring配置文件的位置和名称
        String resource = "ba03/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent02");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

C. 使用省略index属性

Spring配置文件:
在这里插入图片描述

测试方法:

@Test
    public void test033(){
        //指定spring配置文件的位置和名称
        String resource = "ba03/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent03");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

1.2.2 引用类型属性自动注入

对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准的不同,可以分为两种:
byName:根据名称自动注入
byType: 根据类型自动注入

1)byName 方式自动注入

当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
实体类:Student类与School类
Spring配置文件:

	<bean id="myStudent" class="com.suyv.spring.ba04.Student" autowire="byName">
        <property name="name" value="李四"></property>
        <property name="age" value="20"></property>
    </bean>

    <bean id="school" class="com.suyv.spring.ba04.School">
        <property name="name" value="河南科技大学"></property>
        <property name="address" value="河南省洛阳市"></property>
    </bean>

测试方法:

@Test
    public void test04(){
        //指定spring配置文件的位置和名称
        String resource = "ba04/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

2)byType 方式自动注入

使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
实体类:Student类与School类
Spring配置文件:

	<bean id="myStudent" class="com.suyv.spring.ba05.Student" autowire="byType">
        <property name="name" value="李四"></property>
        <property name="age" value="20"></property>
    </bean>

    <bean id="mySchool" class="com.suyv.spring.ba05.School">
        <property name="name" value="河南科技大学"></property>
        <property name="address" value="河南省洛阳市"></property>
    </bean>

测试方法:

@Test
    public void test04(){
        //指定spring配置文件的位置和名称
        String resource = "ba05/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        Student myStudent = (Student)ac.getBean("myStudent");
        System.out.println("Student对象"+myStudent);
    }

执行结果:
在这里插入图片描述

1.2.3 为应用指定多个 Spring 配置文件

在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将 Spring 配置文件分解成多个配置文件。
多个配置文件中有一个总文件,总配置文件将各其它子文件通过<import/>引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。
实体类:Student类与School类
Spring配置文件:
spring-school.xml文件:

	<!--School模块所有bean的声明, School模块的配置文件-->
    <!--声明School对象-->
    <bean id="mySchool" class="com.suyv.spring.ba06.School">
        <property name="name" value="航空大学"/>
        <property name="address" value="北京的海淀区" />
    </bean>

spring-student.xml文件:

    <!--student模块所有bean的声明-->
    <bean id="myStudent" class="com.suyv.spring.ba06.Student"  autowire="byType">
        <property name="name" value="张飒" />
        <property name="age" value="30" />
    </bean>

total.xml文件:
方法1:

	<!--加载文件列表-->
    <import resource="classpath:ba06/spring-school.xml" />
    <import resource="classpath:ba06/spring-student.xml" />

方法2:

    <!--
       在包含关系的配置文件中,可以通配符(*:表示任意字符)
       注意: 主的配置文件名称不能包含在通配符的范围内(不能叫做spring-total.xml)
    -->
    <import resource="classpath:ba06/spring-*.xml" />

测试方法:

@Test
    public void test01(){
      //加载的是总的文件
       String config= "ba06/total.xml";
       ApplicationContext ac = new ClassPathXmlApplicationContext(config);
       //从容器中获取Student对象
       Student myStudent =  (Student) ac.getBean("myStudent");
       System.out.println("student对象="+myStudent);
   }

执行结果:
在这里插入图片描述

1.3 基于注解的 DI

对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变。
需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
在这里插入图片描述
指定多个包的三种方式:

	<!--第一种方式:使用多次组件扫描器,指定不同的包-->
    <context:component-scan base-package="com.suyv.spring.ba01"/>
    <context:component-scan base-package="com.suyv.spring.ba02"/>

    <!--第二种方式:使用分隔符(;或,)分隔多个包名-->
    <context:component-scan base-package="com.suyv.spring.ba01;com.suyv.spring.ba02" />

    <!--第三种方式:指定父包-->
    <context:component-scan base-package="com.suyv.spring" />

1.3.1定义 Bean 的注解@Component

需要在类上使用注解@Component,该注解的 value 属性用于指定该 bean 的 id 值。
实体类:
在这里插入图片描述
spring配置文件:

<context:component-scan base-package="com.suyv.spring.ba01" />

测试代码:

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

执行结果:
在这里插入图片描述

1.3.2 简单类型属性注入@Value

实体类:
在这里插入图片描述
spring配置文件:

<context:component-scan base-package="com.suyv.spring.ba02" />

测试方法:

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

执行结果:
在这里插入图片描述

1.3.3 byType 自动注入@Autowired

实体类:
在这里插入图片描述
在这里插入图片描述

spring配置文件:

    <context:component-scan base-package="com.suyv.spring.ba03" />

测试方法:

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

执行结果:
在这里插入图片描述

1.3.4 byName 自动注入@Autowired 与@Qualifier

需要在引用属性上联合使用注解@Autowired 与@Qualifier。@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。类中无需 set 方法,也可加到 set 方法上。

实体类:
在这里插入图片描述
在这里插入图片描述

spring配置文件:

 <context:component-scan base-package="com.suyv.spring.ba04" />

测试方法:

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

执行结果:
在这里插入图片描述

1.3.5 JDK 注解@Resource 自动注入

Spring提供了对 jdk中@Resource注解的支持。@Resource 注解既可以按名称匹配Bean, 也可以按类型匹配 Bean。默认是按名称注入。使用该注解,要求 JDK 必须是 6 及以上版本。 @Resource 可在属性上,也可在 set 方法上。

实体类:
在这里插入图片描述
在这里插入图片描述
spring配置文件:

	<context:component-scan base-package="com.suyv.spring.ba06" />

测试方法:

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

执行结果:
在这里插入图片描述

1.3.6 注解与 XML 的对比

注解优点是:

方便
直观
高效(代码少,没有配置文件的书写那么复杂)。

其弊端也显而易见:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的
XML 方式优点是:

配置和代码是分离的
在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。

xml 的缺点是:编写麻烦,效率低,大型项目过于复杂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

憨憨浩浩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值