SpringDay02

DI 依赖注入

什么是依赖注入

依赖注入DI(Dependency Injection)

我们先明确依赖的概念

生活中对象之间的依赖关系:

  • 人写字的时候需要依赖笔
  • 人吃饭的时候需要依赖筷子

程序中对象之间的依赖关系:

A类中的方法需要使用到B类对象才能执行,我们说A类依赖B类

那么依赖注入就是将一个复杂的对象中的各个组件赋值装配的过程

最终能够实现,从Spring容器中直接获得赋值装配好的对象的功能

依赖注入程序的实现

下面我们要编写程序实现依赖注入

关羽依赖青龙偃月刀来战斗

关羽这个类中有一个战斗(fight)方法,需要使用到青龙偃月刀对象

1.创建three包

2.创建青龙偃月刀类(DragonBlade)

@Component
public class DragonBlade {

    private String name="青龙偃月刀";
    // 略
}

3.创建关羽类,类中声明青龙偃月刀属性类明确依赖关系

@Component
public class GuanYu {

    private String name="关云长";
    // 明确依赖关系:声明青龙偃月刀属性
    private DragonBlade dragonBlade;

    // 关羽的战斗方法:输出"关云长使用青龙偃月刀战斗"
    public void fight(){
        System.out.println(name+"使用"+dragonBlade.getName()+"战斗");
    }
    // 略
}

4.创建配置类ThreeConfig

@Configuration
@ComponentScan("cn.tedu.three")
public class ThreeConfig {
}

5.编写测试类

@Test
public void three(){
    GuanYu guanYu=acac.getBean("guanYu",GuanYu.class);
    guanYu.fight();
}

运行发生空指针异常

回到GuanYu类

添加@Autowired注解

// 明确依赖关系:声明青龙偃月刀属性
@Autowired
private DragonBlade dragonBlade;

再次运行测试方法

运行输出

关云长使用青龙偃月刀战斗

@Autowired的功能

上面章节中我们使用@Autowired注解实现了依赖注入的效果

我们在GuanYu类DragonBlade属性前添加这个注解就实现了依赖注入效果

导致我们从Spring容器中获得的关羽是自带青龙偃月刀的

具体工作原理如下

在Spring框架实例化GuanYu类时

会检测出DragonBlade属性添加了@Autowired注解

Spring就会在Spring容器中寻找DragonBlade类型的对象

如果找到了就会自动将这个对象赋值给DragonBlade属性

课上作业

按照上面关羽和青龙偃月刀的关系

完成吕布(LvBu)和方天画戟(SkyLance)的依赖关系

经过配置在测试类中输出"吕布使用方天画戟战斗"

@Bean 方式实现依赖注入

我们学习了两种向Spring容器中保存对象的方法

@Bean和组件扫描

上面章节中我们掌握了组件扫描的方式

下面来学习@Bean的方式

我们使用张飞和丈八蛇矛的例子来实现

创建cn.tedu.fei包

创建SnakeLance类

public class SnakeLance {

    private String name="丈八蛇矛";

    // get\set略

    @Override
    public String toString() {
        return name;
    }
}

创建张飞ZhangFei类

public class ZhangFei {

    private String name="张翼德";
    private SnakeLance snakeLance;

	// get\set略

    public void fight(){
        System.out.println(name+"使用"+snakeLance+"战斗");
    }
}

创建FeiConfig类来使用@Bean将对象保存在Spring容器中

@Configuration
public class FeiConfig {

    @Bean
    public SnakeLance lance(){
        return new SnakeLance();
    }

    // @Bean标记的方法的参数列表中如果声明了参数
    // Spring会自动从Spring容器中寻找合适对象,为这个参数赋值
    // 也就是说上面保存到Spring容器中的lance对象,就会自动赋值给参数sl
    // 方法中又将sl赋值给了zf的属性,所以实现了依赖注入
    @Bean
    public ZhangFei fei(SnakeLance sl){
        ZhangFei zf=new ZhangFei();
        // 将丈八蛇矛类型的参数赋值给zf对象依赖的属性
        zf.setSnakeLance(sl);
        return zf;
    }

}

测试类和之前套路一直

最终测试代码

@Test
public void fei(){
    ZhangFei zf=acac.getBean("fei",ZhangFei.class);
    zf.fight();
}

@Bean依赖注入失败情况

上面章节顺利完成依赖注入是因为Spring容器中恰巧包含需要依赖的对象

如果Spring容器中没有丈八蛇矛

测试类运行就会发生错误

错误信息中包含:

“expected at least 1 bean”

表示当前Spring容器没有任何一个匹配类型的对象

除了Spring容器中没有匹配对象引发错误之外

还有另一种情况也可能引发错误

如果Spring容器中有两把以上的丈八蛇矛对象

也可能发生依赖注入失败的情况

FeiConfig类修改为

@Bean
public SnakeLance lance1(){
    return new SnakeLance();
}
@Bean
public SnakeLance lance2(){
    return new SnakeLance();
}

可能发生下面的错误

“expected single matching bean but found 2: lance1,lance2”

表示当前Spring容器中有多个匹配对象

但是Spring无法自动选择其中的某一个成为我们依赖的对象

我们需要将@Bean保存张飞的方法的参数名和其中一个丈八蛇矛对象的id匹配

才能在多个丈八蛇矛中选择其中一个,完成依赖注入

@Bean
public ZhangFei zhangFei(SnakeLance lance1){
    ZhangFei zf=new ZhangFei();
    zf.setSnakeLance(lance1);
    return zf;
}

组件扫描依赖注入的失败情况

@Bean依赖注入可能会出现失败

组件扫描也一样

以three包中的关羽青龙偃月刀的例子上修改

首先删除DragonBlade类上的@Component注解

然后修改ThreeConfig配置如下

@Configuration
@ComponentScan("cn.tedu.three")
public class ThreeConfig {

    // 为了测试组件扫描的依赖注入失败
    // 我们注入两把青龙偃月刀对象
    @Bean
    public DragonBlade blade1(){
        return new DragonBlade();
    }
    @Bean
    public DragonBlade blade2(){
        return new DragonBlade();
    }

}

再去运行ThreeTest类的测试方法

也会发生依赖注入失败的错误

解决这个错误的办法有两个

  • 将@Autowired注解标记的属性名称修改为匹配的id名称
  • 在@Autowired注解下添加@Qualifier注解,并指定要匹配的id名称

如果采用修改属性名的办法,势必会带来较多代码的维护和修改,不推荐使用

这里推荐使用@Qualifier注解来选择匹配的id

@Autowired
@Qualifier("blade1")
private DragonBlade dragonBlade;

指定之后,再次测试运行成功!

Ioc\DI解耦

什么是耦合

解耦:解开耦合

让程序从紧耦合状态转换为松耦合状态的过程

所以我们要先明确什么是耦合

耦合的概念:指程序中的各个组件(对象)互相依赖的紧密程度

​ 如果依赖关系容易更换,那么它们的依赖程度就是不紧密的

​ 如果依赖关系不容易更换,那么它们的依赖程度就是就紧密的

关系紧密,耦合就高\紧,需要修改代码时,影响代码的代码就多

关系不紧密,耦合就低\松,需要修改代码时,影响代码的代码就少

在程序中,大部分情况下,我们要为代码的扩展和维护提供更广的空间,编写的代码都要追求低耦合

我们之前章节中,关羽和青龙偃月刀就是紧耦合的,因为关系不能使用除青龙偃月刀之外的任何武器

要想实现松耦合的程序,关键的一步就是将关羽的依赖类型,从之前的青龙偃月刀这样的具体类型,变更为一个抽象的类型(接口和抽象类)

编写解耦的程序

我们创建一个包cn.tedu.ou

然后创建一个武器接口Weapon

public interface Weapon {

    // 我们声明一个武器都能用到的方法
    // 获得武器名称,在fight方法输出时都需要用
    String getName();

}

然后创建两个武器接口的实现类

@Component
public class DragonBlade implements Weapon {
    private String name="青龙偃月刀";
    // 其它代码略
}
@Component
public class SkyLance implements  Weapon {
    private String name="方天画戟";
    // 其它代码略
}

创建关羽类

@Component
public class GuanYu {

    private String name="关二爷";
    // 依赖关系由之前的具体的类型,修改为抽象的接口类型,实现解耦
    // 运行时Spring会从Spring容器中寻找Weapon接口的实现类对象来自动赋值给Weapon
    // 更换依赖对象,只需要维护保存在Spring容器中的Weapon实现类即可
    @Autowired
    private Weapon weapon;

    public void fight(){
        System.out.println(name+"使用"+weapon.getName()+"战斗");
    }
    //其它代码略
}

编写OuConfig

@Configuration
@ComponentScan("cn.tedu.ou")
public class OuConfig {
}

继续编写测试类代码如下

@Test
public void ou(){
    GuanYu guanYu=acac.getBean("guanYu",GuanYu.class);
    guanYu.fight();
}

测试类运行报错,末尾的信息:

“expected single matching bean but found 2: dragonBlade,snakeLance”

意思为当前Spring容器中属于Weapon类型的实现类的对象有两个

这个两个对象需要我们选择其中一个来进行依赖注入

我们办法:

1.将不需要的对象的@Component注解删掉,留下需要的类的@Component注解,但是类比较多时,维护也比较麻烦

2.使用我们学习的@Qualifier注解来指定需要的对象的id

@Autowired
@Qualifier("skyLance")
private Weapon weapon;

再次运行输出

“关二爷使用方天画戟战斗”

}


测试类运行报错,末尾的信息:

"expected single matching bean but found 2: dragonBlade,snakeLance"

意思为当前Spring容器中属于Weapon类型的实现类的对象有两个

这个两个对象需要我们选择其中一个来进行依赖注入

我们办法:

1.将不需要的对象的@Component注解删掉,留下需要的类的@Component注解,但是类比较多时,维护也比较麻烦

2.使用我们学习的@Qualifier注解来指定需要的对象的id

```java
@Autowired
@Qualifier("skyLance")
private Weapon weapon;

再次运行输出

“关二爷使用方天画戟战斗”

SpringBoot聚合项目

什么是聚合项目

Maven提供的一种项目结构

简单来说,就是我们的项目是一个父级项目,其中可以创建多个子项目的结构

每个子项目编写自己的代码,和其它子项目互不干扰

每个子项目开发自己的功能,方便项目的模块化开发和维护

创建聚合项目

以商城为例

一个商城项目要分为很多模块,最典型的就是前台和后台

一般来说一定是两个项目

先来创建父项目

在这里插入图片描述

删除创建之后出现的src文件夹

因为父项目不会编写代码

创建完父项目修改它的pom文件内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>jd</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jd</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <!--
          下面的配置表示当前项目只是一个pom文件没有具体代码
          当一个子项目继承这个父项目时,相当于只继承了这个项目的pom文件
    -->
    <packaging>pom</packaging>

</project>

创建子项目

在父项目名称上单击右键选择new->module

在这里插入图片描述
在这里插入图片描述

创建项目即可

父项目和子项目有一个确认关系的配置过程

我们称之为父子相认

父项目认儿子

<!--
          下面的配置表示当前项目只是一个pom文件没有具体代码
          当一个子项目继承这个父项目时,相当于只继承了这个项目的pom文件
    -->
    <packaging>pom</packaging>
    <!--
        modules标签中声明当前父项目包含的所有子项目的名称
        也就是父认子的配置
    -->
    <modules>
        <module>jd-shop</module>
<!--        <module></module>-->
    </modules>

子项目的pom文件也需要配置

就是儿子人父亲的过程

将父项目pom文件的第1113行复制到子项目pom文件的第68行

<parent>
    <groupId>cn.tedu</groupId>
    <artifactId>jd</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

这样就完成父子相认了

我们要开发的项目都是这样的父项目和子项目的结构

课堂练习

按照刚刚的过程

创建jd的后台项目jd-backend

完成父子相认

有额外时间的同学,可以从创建父项目开始做一遍

达内知道项目概述

达内知道项目基本功能

<<达内知道>>项目的曾用名为<<稻草问答>>

是一个学生和讲师进行问题交流的在线互通平台

在这里插入图片描述

达内知道项目创建

使用聚合项目的方式进行创建

创建父项目knows

在这里插入图片描述

什么都不需要勾选

将父项目的pom文件修改为

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>knows</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>knows</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <packaging>pom</packaging>

</project>

创建聚合子项目

knows-portal(门户)
在这里插入图片描述

勾选SpringWeb选项

然后进行父子相认

父项目pom文件

<modules>
    <module>knows-portal</module>
</modules>

子项目pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>knows</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath />
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>knows-portal</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>knows-portal</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

达内知道git地址:https://gitee.com/jtzhanghl/knows2111.git

加载数据库数据

我们之前使用命令行来错误mysql太麻烦了

在企业中工作不可能使用效率那么低的工具做数据库的操作

我们可以使用mysql\MariaDB的可视化工具软件来提高操作数据库的效率

如果安装的是苍老师网站提供的MariaDB的安装包,会在系统中安装一个可视化工具软件HeidiSQL

这个一个免费的具有基本功能的数据库可视化工具

如果安装的mysql不包含HeidiSQL软件,我们可以上网搜索类似软件来使用

例如sqlyog等,以达到相同的功能

我们今后就可以使用heidiSQL来操作数据了

下面就解压提供给大家的knows_v4.zip压缩包

将解压后文件夹中的knows_v4.sql文件中的内容复制

粘贴到查询页面然后运行

这样就加载了我们达内知道项目的数据

运行过程中出现56个警告或28个警告都是正常的!

达内知道项目数据库结构简介

上面数据加载后,创建了knows数据库

其中包含了14张表

这14张表可以分为两块

  • 用户管理模块:涉及用户数据操作的相关表,用户,权限,角色,班级等
  • 问答管理模块:涉及提问和回答操作相关表,问题,回答,评论,标签等

数据结构如图

在这里插入图片描述

加载静态资源

一个网站有了数据是第一步

然后还有制作页面,用户显示

我们学习的是java,主要做后端代码,开发页面不是我们的主要职责

所以页面直接发给大家,包含样式和js等

knows_v4文件夹中的"原型网页"文件夹中的所有内容

复制到portal项目的static目录下

image-20220303175152294

启动knows-portal项目

在启动之后

浏览器地址栏输入

localhost:8080/index_student.html

测试是否能够正常访问静态资源

英文

Dependency :依赖

Injection:注入

expected:期望

single:单独的

match:匹配

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值