Spring入门(二)快速入门 – IOC/DI

导读:本篇文章讲解 Spring入门(二)快速入门 – IOC/DI,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

Spring系列文章目录

Spring入门(一)浅谈Spring
Spring入门(二)快速入门 – IOC/DI

  • Spring系列持续更新中…


前言

一、Spring核心之 IOC 、DI

1. IOC

IOC(Inversion of Control):控制反转
控制反转指的是将对象的创建、管理权限从我们程序猿的手里,移交给我们Spring框架。
这时我们不再有创建、管理对象的主动权,改为被动的接收、使用,这种控制权的转换我们称之为控制反转。

主动控制:适合创建简单对象。
控制反转:适合管理创建过程复杂的对象。

2. DI

DI(Dependency Injection):依赖注入
依赖注入指的是在程序运行期间,由外部容器(Spring)动态的将依赖对象注入到组件中。其实IOC 和 DI 其实是同一个概念。依赖注入是实现控制反转的方式。
目的:解耦
关系:has a

从概念来讲,实际太过于抽象,作为刚刚接触Spring框架的小伙伴们来说,真心不能够理解,实际我也曾经是其中的一员。但是对于操作来讲极其简便。这就是我上文说到的,刚刚学习框架,要做到不求甚解。

举个例子:
我们要完成某样有实际意义的功能,一般来讲都需要两个或两个以上的类组成,并互相之间协作完成的结果。按照传统来讲,我们的每个对象都需要管理和自己互相协作的对象(它所以依赖的对象)的引用,这将导致高度耦合。
而如果我们通过DI,这种对象的依赖关系就由Spring这个框架去进行管理,那我们就实现了松耦合。其次我们现在都是基于接口编程,也是使得其解耦低的原因所在,实现了可替换性。

在这里插入图片描述
面向接口编程(解耦 / 松耦合)
在这里插入图片描述

二、第一个Spring项目

1. IOC – 代码实现

1.1 第一种方式:@Configuration + @Bean

项目结构:
在这里插入图片描述

  1. 创建一个 Maven 项目,详情可参考:简单maven项目的创建

  2. 导入依赖 (pom.xml)

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
    </dependencies>
    

    pom.xml 文件 如图所示:
    在这里插入图片描述

  3. 创建JavaBean – DemoBean

    /**
     * @Author lss
     */
    public class DemoBean {
    }
    
  4. 创建配置类

    /**
     * @Author lss
     */
    @Configuration
    public class Config {
    
        @Bean
        public DemoBean getDemoBean() {
            return new DemoBean();
        }
    
    }
    
  5. 测试 DemoBean 对象是否交给Spring去管理

    /**
     * @Author lss
     */
    public class IOCTest {
        public static void main(String[] args) {
            // 初始化Spring容器
            ApplicationContext ac =
                    new AnnotationConfigApplicationContext(Config.class);
            // 获取被管理的JavaBean
            DemoBean bean = ac.getBean(DemoBean.class);
            System.out.println(bean);
        }
    }
    

    当然这里如果已经对于Juint 单元测试 有些了解的情况下,我们测试也可以使用 Juint,能达到同样的效果

    在 pom.xml 文件中 导入 Juint 单元测试依赖

    <!-- 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    

    pom.xml 文件 如图所示:
    在这里插入图片描述

    @Test
    public void testIOC() {
        // 初始化Spring容器
        ApplicationContext ac =
                new AnnotationConfigApplicationContext(Config.class);
        // 获取被管理的JavaBean
        DemoBean bean = ac.getBean(DemoBean.class);
        System.out.println(bean);
    }
    

    如图所示:
    在这里插入图片描述
    运行输出结果为:
    在这里插入图片描述

1.2 第二种方式:@Component + @ComponentScan 组件扫描

  • 创建JavaBean – ExampleBean,类上添加 @Component 注解

    /**
     * @Author lss
     */
    @Component
    public class ExampleBean {
    }
    
  • 在配置类上,添加 @ComponentScan 注解

    /**
     * @Author tedu-sysh-lrf
     */
    @Configuration
    @ComponentScan("cn.cy.bean")
    public class Config {
    
        @Bean
        public DemoBean getDemoBean() {
            return new DemoBean();
        }
    
    }
    
  • 测试
    在这里插入图片描述
    运行输出结果为:
    在这里插入图片描述

2. DI – 代码实现

DI(依赖注入) 在上面讲述概念的时候已经提到过了,咱们这里再简单的剖析下:
依赖注入实际来讲分为两部分:

  • 依赖(dependency)
    实际依赖我们之前学习 maven 项目的时候就已经接触过这个名词 ,添加依赖 / 导入依赖…
    那么什么才是我们的依赖呢?
    依赖通俗意义上来讲,是指一个业务功能执行期间所需要的前提:煮米饭必须以米为前提,砍树需要以工具为前提。

    <dependencies>
        <!-- spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  • 注入
    注入是指将我们需要的依赖给到 / 传递到使用者,我们称为注入。
    实际我们在获取这个依赖的时候可以通过两种方式:主动获取(对象自己创建),和被动得到(对象别人创建,给只管使用即可)。而我们被动得到我们称之为注入。
    以煮饭为例:米的生产过程我不需要关注,我只需要去使用即可,这个就是我们被动得到。
    以砍树为例:工具的生产过程我不需要关注,我只需要去使用即可,这个就是我们被动得到。

我们这里还是以刚才的项目进行使用测试。
在这里插入图片描述

  1. 创建一个 Maven 项目,详情可参考:简单maven项目的创建

  2. 导入依赖 (pom.xml)

    <dependencies>
       <!-- spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  3. 创建JavaBean – Saw / Worker
    Saw

    /**
     * @Author lss
     */
    public class Saw implements Serializable {
    
        private String name = "电锯";
    
        @Override
        public String toString() {
            return name;
        }
    }
    

    Worker

    /**
     * @Author lss
     */
    public class Worker implements Serializable {
    
        private String name = "光头强";
    
        public Saw saw;
    
        public void work() {
            System.out.println(name +"使用" + saw + "砍树");
        }
    }
    
  4. 创建配置类

    /**
     * @Author lss
     */
    @Configuration
    public class Config {
    
        @Bean
        public Saw saw() {
            return new Saw();
        }
    
        @Bean
        public Worker worker(Saw s) {
            Worker worker = new Worker();
            worker.saw = s;
            return worker;
        }
    
    }
    
  5. 创建测试类,测试,Saw对象是否被注入到 Worker对象中

    /**
     * @Author tlss
     */
    public class DITests {
    
        @Test
        public void testDI() {
            ApplicationContext ac =
                    new AnnotationConfigApplicationContext(Config.class);
            Worker bean = ac.getBean("worker",Worker.class);
            bean.work();
        }
    
    }
    

运行输出结果为:
在这里插入图片描述

2.1 Spring IOC组件注入时组件自动匹配规则

  • 首先按照注入参数类型查找响应类型的Bean组件,如果没有则直接报错
  • 如果在Spring容器中能够匹配上唯一类型的Bean组件,则进行注入成功
  • 如果按照类型匹配到两个或两个以上的bean组件,则在查找组件ID和变量名是否匹配,如果匹配则注入成功
  • 如果组件类型和组件ID都不能很好的匹配则报错

2.2 @Autowired

注解方式进行注入:
修改上述代码:
通过@Component将 Saw 和 Worker 对象交给Spring去管理
在这里插入图片描述
通过 @Autowired 注解,将 Saw 对象注入进去
在这里插入图片描述
在配置类上添加 @ComponentScan 注解,扫描组件
在这里插入图片描述
同样进行测试,得到相同的结果
在这里插入图片描述
一般来讲,我们开发中这种方式使用更加简便,也是我们常常使用的方式。

2.3 接口解耦

面向接口编程(解耦 / 松耦合)
在这里插入图片描述
我们在上述代码上进行修改即可
添加 工具接口 Tool
在这里插入图片描述
添加 具体的工具-斧子 Ax ,实现工具接口Tool,并添加@Component注解
在这里插入图片描述
修改 具体的工具-锯 Saw ,实现工具接口Tool
在这里插入图片描述

修改 Worker类 ,修改注入对象,将注入对象类型改为接口类型
在这里插入图片描述
运行测试类:
这时我们的程序会报错,这个是正常的现象,或者说是我们想要出现的效果,这里我们来看下报错信息,分析下报错原因
在这里插入图片描述

这里出现了一个异常:NoUniqueBeanDefinitionException 不唯一的bean定义异常
异常错误描述:

没有一个合适的bean类型(cn.cy.bean.Tool)可用,预期有一个单独的匹配的bean,但是找到了 2个 (saw,ax)
这里可以理解为,当我们想把工具注入到Worker对象中时,Spring容器找到了两个Tool工具类型,不知道应该注入哪个类型了,所以会抛出一个 NoUniqueBeanDefinitionException 异常。

解决办法:

这时,我们只需要去指定一下我们我们想要注入的类型即可

那这里需要先了解下@Autowired的注入规则

2.3 @Autowired的注入规则

  • 首先按照类型进行注入(byType),如果没有则直接报错
  • 如果在 Spring容器 中能够匹配到唯一类型的 Bean 组件,则注入成功
  • 如果按照类型匹配到两个或两个以上的组件,则再查找组件ID和变量名是否匹配(byType),如果匹配则注入成功
  • 如果组件类型和组件ID都不能很好的匹配则报错

根据上面的注入规则,有以下两种解决办法:

  1. 利用组件自定义ID,当组件ID设置为 tool 时, @Autowired 注解会根据ID匹配成功
  2. 利用注解 @Qualifier(“beanID”)指定注入bean组件的ID

第一种解决办法:
将具体想要注入的组件,自己定义ID(名字),这样和要注入的名字一致,这样就可以注入进去了,但是这种方式不太常见,我们一般都是保证原生默认的beanID
在这里插入图片描述第二种解决办法:
直接在要注入的地方添加 @Qualifier 注解,告诉 Spring容器通过 指定的beanID(名字)进行注入
在这里插入图片描述

如想了解其他异常,可见常见异常汇总:

  • 常见异常汇总链接:xxx(更新中…)

3. 专有名词

3.1 Java Bean

Bean 的英文意思是 “豆子”

JavaBean 是一种约定 Java 类的定义规范,使得我们程序规范一致,方便使用,交流。它是企业通用的一种编程标准,建议大家都去遵守。
约定:

  • 需要定义包 package
  • 有无参的构造方法(无参构造器)
  • 需要实现序列化接口
  • 类中声明 getXxx 和 setXxx 方法(getter ,setter 方法)

Spring 同样建议被其管理的对象符合 JavaBean 规范。并且我们通常意义上称呼的 JavaBean对象 就是由 Spring 容器管理的对象,我们也称 Spring 为 Spring容器,IOC容器…

4. 注解

如想了解其他注解 / 注解的具体用法,可见常见异常汇总:

  • 常见注解汇总链接:xxx(更新中…)

4.1 @Bean

告诉 Spring 在启动时,加载被 @Bean 标注的方法,返回值就是 Spring 创建的对象(交给 Spring 管理的对象)方法名是 Bean 的ID

4.2 @Configuration

由 @Configuration 标注的类,告诉 Spring 它是一个配置类

4.3 @Component

通用组件注解
下面的组件注解是 @Component 注解的衍生注解,主要目的是为了提高标记代码的 “可读性”

4.3.1 @Controller

控制层组件注解

4.3.2 @Service

业务层组件注解

3.3.3 @Repository

持久层组件注解

4.4 @ComponentScan

@ComponentScan 作用是根据定义的扫描路径,把符合扫描规则的类装配到 Spring 容器中

4.5 @Autowired

自动注入注解

4.6 @Qualifier

与 @Autowired 配合使用,当存在多个实例的时候,指定具体实例的名称

4.7 @Test

junit 单元测试注解

总结

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/107664.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!