Spring入门-IOC/DI注解管理与整合mybatis及Junit(2)

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    1核心容器

    前面已经完成bean与依赖注入的相关知识学习接下来我们主要学习的是IOC容器中的核心容器

    这里所说的核心容器大家可以把它简单的理解为ApplicationContext前面虽然已经用到过但是并没有系统的学习接下来咱们从以下几个问题入手来学习下容器的相关知识:

    • 如何创建容器?
    • 创建好容器后如何从容器中获取bean对象?
    • 容器类的层次结构是什么?
    • BeanFactory是什么?

    1.1 环境准备

    在学习和解决上述问题之前先来准备下案例环境:

    • 创建一个Maven项目

    • pom.xml添加Spring的依赖

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
    • resources下添加applicationContext.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">
          <bean id="bookDao" class="com.java.dao.impl.BookDaoImpl"/>
      </beans>
      
    • 添加BookDao和BookDaoImpl类

      public interface BookDao {
          public void save();
      }
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      
    • 创建运行类App

      public class App {
          public static void main(String[] args) {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
              BookDao bookDao = (BookDao) ctx.getBean("bookDao");
              bookDao.save();
          }
      }
      

    最终创建好的项目结构如下:

    1629982672522

    1.2 容器

    1.2.1 容器的创建方式

    案例中创建ApplicationContext的方式为:

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    

    这种方式翻译为:类路径下的XML配置文件

    除了上面这种方式Spring还提供了另外一种创建方式为:

    ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
    

    这种方式翻译为:文件系统下的XML配置文件

    使用这种方式运行会出现如下错误:

    1629983245121

    从错误信息中能发现这种方式是从项目路径下开始查找applicationContext.xml配置文件的所以需要将其修改为:

    ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml"); 
    

    **说明:**大家练习的时候写自己的具体路径。

    这种方式虽能实现但是当项目的位置发生变化后,代码也需要跟着改,耦合度较高,不推荐使用。

    1.2.2 Bean的三种获取方式

    方式一就是目前案例中获取的方式:

    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    

    这种方式存在的问题是每次获取的时候都需要进行类型转换有没有更简单的方式呢?

    方式二

    BookDao bookDao = ctx.getBean("bookDao"BookDao.class);
    

    这种方式可以解决类型强转问题但是参数又多加了一个相对来说没有简化多少。

    方式三:

    BookDao bookDao = ctx.getBean(BookDao.class);
    

    这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。

    1.2.3 容器类层次结构

    (1)在IDEA中双击shift,输入BeanFactory

    1629985148294

    (2)点击进入BeanFactory类ctrl+h,就能查看到如下结构的层次关系

    1629984980781

    从图中可以看出容器类也是从无到有根据需要一层层叠加上来的大家重点理解下这种设计思想。

    1.2.4 BeanFactory的使用

    使用BeanFactory来创建IOC容器的具体实现方式为:

    public class AppForBeanFactory {
        public static void main(String[] args) {
            Resource resources = new ClassPathResource("applicationContext.xml");
            BeanFactory bf = new XmlBeanFactory(resources);
            BookDao bookDao = bf.getBean(BookDao.class);
            bookDao.save();
        }
    }
    

    为了更好的看出BeanFactoryApplicationContext之间的区别在BookDaoImpl添加如下构造函数:

    public class BookDaoImpl implements BookDao {
        public BookDaoImpl() {
            System.out.println("constructor");
        }
        public void save() {
            System.out.println("book dao save ..." );
        }
    }
    

    如果不去获取bean对象打印会发现

    • BeanFactory是延迟加载只有在获取bean对象的时候才会去创建

    • ApplicationContext是立即加载容器加载的时候就会创建bean对象

    • ApplicationContext要想成为延迟加载只需要按照如下方式进行配置

      <?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 id="bookDao" class="com.java.dao.impl.BookDaoImpl"  lazy-init="true"/>
      </beans>
      

    小结

    这一节中所讲的知识点包括:

    • 容器创建的两种方式

      • ClassPathXmlApplicationContext[掌握]
      • FileSystemXmlApplicationContext[知道即可]
    • 获取Bean的三种方式

      • getBean(“名称”):需要类型转换
      • getBean(“名称”,类型.class):多了一个参数
      • getBean(类型.class):容器中不能有多个该类的bean对象

      上述三种方式各有各的优缺点用哪个都可以。

    • 容器类层次结构

      • 只需要知晓容器的最上级的父接口为 BeanFactory即可
    • BeanFactory

      • 使用BeanFactory创建的容器是延迟加载
      • 使用ApplicationContext创建的容器是立即加载
      • 具体BeanFactory如何创建只需要了解即可。

    1.2 核心容器总结

    这节中没有新的知识点只是对前面知识的一个大总结共包含如下内容:

    1.2.1 容器相关

    • BeanFactory是IoC容器的顶层接口初始化BeanFactory对象时加载的bean延迟加载
    • ApplicationContext接口是Spring容器的核心接口初始化时bean立即加载
    • ApplicationContext接口提供基础的bean操作相关方法通过其他接口扩展其功能
    • ApplicationContext接口常用初始化类
      • ClassPathXmlApplicationContext(常用)
      • FileSystemXmlApplicationContext

    1.2.2 bean相关

    1629986510487

    其实整个配置中最常用的就两个属性idclass

    把scope、init-method、destroy-method框起来的原因是后面注解在讲解的时候还会用到所以大家对这三个属性关注下。

    1.2.3 依赖注入相关

    1629986848563

    2IOC/DI注解开发

    Spring的IOC/DI对应的配置开发就已经讲解完成但是使用起来相对来说还是比较复杂的复杂的地方在配置文件

    前面咱们聊Spring的时候说过Spring可以简化代码的开发到现在并没有体会到。

    所以Spring到底是如何简化代码开发的呢?

    要想真正简化开发就需要用到Spring的注解开发Spring对注解支持的版本历程:

    • 2.0版开始支持注解
    • 2.5版注解功能趋于完善
    • 3.0版支持纯注解开发

    关于注解开发我们会讲解两块内容注解开发定义bean纯注解开发

    注解开发定义bean用的是2.5版提供的注解纯注解开发用的是3.0版提供的注解。

    2.1 环境准备

    在学习注解开发之前先来准备下案例环境:

    • 创建一个Maven项目

    • pom.xml添加Spring的依赖

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
    • resources下添加applicationContext.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">
          <bean id="bookDao" class="com.java.dao.impl.BookDaoImpl"/>
      </beans>
      
    • 添加BookDao、BookDaoImpl、BookService、BookServiceImpl类

      public interface BookDao {
          public void save();
      }
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      public interface BookService {
          public void save();
      }
      
      public class BookServiceImpl implements BookService {
          public void save() {
              System.out.println("book service save ...");
          }
      }
      
      
    • 创建运行类App

      public class App {
          public static void main(String[] args) {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
              BookDao bookDao = (BookDao) ctx.getBean("bookDao");
              bookDao.save();
          }
      }
      

    最终创建好的项目结构如下:

    1629989221808

    2.2 注解开发定义bean

    在上述环境的基础上我们来学一学Spring是如何通过注解实现bean的定义开发?

    步骤1:删除原XML配置

    将配置文件中的<bean>标签删除掉

    <bean id="bookDao" class="com.java.dao.impl.BookDaoImpl"/>
    

    步骤2:Dao上添加注解

    在BookDaoImpl类上添加@Component注解

    @Component("bookDao")
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ..." );
        }
    }
    

    注意:@Component注解不可以添加在接口上因为接口是无法创建对象的。

    XML与注解配置的对应关系:

    1629990315619

    步骤3:配置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"
           xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <context:component-scan base-package="com.java"/>
    </beans>
    

    说明:

    component-scan

    • component:组件,Spring将管理的bean视作自己的一个组件
    • scan:扫描

    base-package指定Spring框架扫描的包路径它会扫描指定包及其子包中的所有类上的注解。

    • 包路径越多[如:com.java.dao.impl]扫描的范围越小速度越快
    • 包路径越少[如:com.java],扫描的范围越大速度越慢
    • 一般扫描到项目的组织名称即Maven的groupId下[如:com.java]即可。

    步骤4运行程序

    运行App类查看打印结果

    1630027590558

    步骤5:Service上添加注解

    在BookServiceImpl类上也添加@Component交给Spring框架管理

    @Component
    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    

    步骤6:运行程序

    在App类中从IOC容器中获取BookServiceImpl对应的bean对象打印

    public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            System.out.println(bookDao);
            //按类型获取bean
            BookService bookService = ctx.getBean(BookService.class);
            System.out.println(bookService);
        }
    }
    

    打印观察结果两个bean对象都已经打印到控制台

    1630027743910

    说明:

    • BookServiceImpl类没有起名称所以在App中是按照类型来获取bean对象

    • @Component注解如果不起名称会有一个默认值就是当前类名首字母小写所以也可以按照名称获取如

      BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
      System.out.println(bookService);
      

    对于@Component注解还衍生出了其他三个注解@Controller@Service@Repository

    通过查看源码会发现:

    1630028345074

    这三个注解和@Component注解的作用是一样的为什么要衍生出这三个呢?

    方便我们后期在编写类的时候能很好的区分出这个类是属于表现层业务层还是数据层的类。

    知识点1:@Component等

    名称@Component/@Controller/@Service/@Repository
    类型类注解
    位置类定义上方
    作用设置该类为spring管理的bean
    属性value默认定义bean的id

    2.2 纯注解开发模式

    上面已经可以使用注解来配置bean,但是依然有用到配置文件在配置文件中对包进行了扫描Spring在3.0版已经支持纯注解开发

    • Spring3.0开启了纯注解开发模式使用Java类替代配置文件开启了Spring快速开发赛道

    具体如何实现?

    2.2.1 思路分析

    实现思路为:

    • 将配置文件applicationContext.xml删除掉使用类来替换。

    2.2.2 实现步骤

    步骤1:创建配置类

    创建一个配置类SpringConfig

    public class SpringConfig {
    }
    
    
    步骤2:标识该类为配置类

    在配置类上添加@Configuration注解将其标识为一个配置类,替换applicationContext.xml

    @Configuration
    public class SpringConfig {
    }
    
    步骤3:用注解替换包扫描配置

    在配置类上添加包扫描注解@ComponentScan替换<context:component-scan base-package=""/>

    @Configuration
    @ComponentScan("com.java")
    public class SpringConfig {
    }
    
    步骤4:创建运行类并执行

    创建一个新的运行类AppForAnnotation

    public class AppForAnnotation {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
            System.out.println(bookDao);
            BookService bookService = ctx.getBean(BookService.class);
            System.out.println(bookService);
        }
    }
    

    运行AppForAnnotation,可以看到两个对象依然被获取成功

    1630029110506

    至此纯注解开发的方式就已经完成了主要内容包括:

    • Java类替换Spring核心配置文件

      1630029254372

    • @Configuration注解用于设定当前类为配置类

    • @ComponentScan注解用于设定扫描路径此注解只能添加一次多个数据请用数组格式

      @ComponentScan({com.java.service","com.java.dao"})
      
    • 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象

      //加载配置文件初始化容器
      ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
      //加载配置类初始化容器
      ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
      

    知识点1@Configuration

    名称@Configuration
    类型类注解
    位置类定义上方
    作用设置该类为spring配置类
    属性value默认定义bean的id

    知识点2@ComponentScan

    名称@ComponentScan
    类型类注解
    位置类定义上方
    作用设置spring配置类扫描路径用于加载使用注解格式定义的bean
    属性value默认扫描路径此路径可以逐层向下扫描

    小结:

    这一节重点掌握的是使用注解完成Spring的bean管理需要掌握的内容为:

    • 记住@Component、@Controller、@Service、@Repository这四个注解
    • applicationContext.xml中<context:component-san/>的作用是指定扫描包路径注解为@ComponentScan
    • @Configuration标识该类为配置类使用类替换applicationContext.xml文件
    • ClassPathXmlApplicationContext是加载XML配置文件
    • AnnotationConfigApplicationContext是加载配置类

    2.3 注解开发bean作用范围与生命周期管理

    使用注解已经完成了bean的管理接下来按照前面所学习的内容将通过配置实现的内容都换成对应的注解实现包含两部分内容:bean作用范围bean生命周期

    2.3.1 环境准备

    老规矩学习之前先来准备环境:

    • 创建一个Maven项目

    • pom.xml添加Spring的依赖

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
    • 添加一个配置类SpringConfig

      @Configuration
      @ComponentScan("com.java")
      public class SpringConfig {
      }
      
    • 添加BookDao、BookDaoImpl类

      public interface BookDao {
          public void save();
      }
      @Repository
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      
    • 创建运行类App

      public class App {
          public static void main(String[] args) {
              AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
              BookDao bookDao1 = ctx.getBean(BookDao.class);
              BookDao bookDao2 = ctx.getBean(BookDao.class);
              System.out.println(bookDao1);
              System.out.println(bookDao2);
          }
      }
      

    最终创建好的项目结构如下:

    1630031112993

    2.3.2 Bean的作用范围

    (1)先运行App类,在控制台打印两个一摸一样的地址说明默认情况下bean是单例

    1630031192753

    (2)要想将BookDaoImpl变成非单例只需要在其类上添加@scope注解

    @Repository
    //@Scope设置bean的作用范围
    @Scope("prototype")
    public class BookDaoImpl implements BookDao {
    
        public void save() {
            System.out.println("book dao save ...");
        }
    }
    

    再次执行App类打印结果:

    1630031808947

    知识点1@Scope
    名称@Scope
    类型类注解
    位置类定义上方
    作用设置该类创建对象的作用范围
    可用于设置创建出的bean是否为单例对象
    属性value默认定义bean作用范围
    默认值singleton单例可选值prototype非单例

    2.3.3 Bean的生命周期

    (1)在BookDaoImpl中添加两个方法initdestroy,方法名可以任意

    @Repository
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
        public void init() {
            System.out.println("init ...");
        }
        public void destroy() {
            System.out.println("destroy ...");
        }
    }
    
    

    (2)如何对方法进行标识哪个是初始化方法哪个是销毁方法?

    只需要在对应的方法上添加@PostConstruct@PreDestroy注解即可。

    @Repository
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
        @PostConstruct //在构造方法之后执行替换 init-method
        public void init() {
            System.out.println("init ...");
        }
        @PreDestroy //在销毁方法之前执行,替换 destroy-method
        public void destroy() {
            System.out.println("destroy ...");
        }
    }
    
    

    (3)要想看到两个方法执行需要注意的是destroy只有在容器关闭的时候才会执行所以需要修改App的类

    public class App {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            BookDao bookDao1 = ctx.getBean(BookDao.class);
            BookDao bookDao2 = ctx.getBean(BookDao.class);
            System.out.println(bookDao1);
            System.out.println(bookDao2);
            ctx.close(); //关闭容器
        }
    }
    

    (4)运行App,类查看打印结果证明init和destroy方法都被执行了。

    1630032385498

    注意:@PostConstruct和@PreDestroy注解如果找不到需要导入下面的jar包

    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
    

    找不到的原因是从JDK9以后jdk中的javax.annotation包被移除了这两个注解刚好就在这个包中。

    知识点1@PostConstruct
    名称@PostConstruct
    类型方法注解
    位置方法上
    作用设置该方法为初始化方法
    属性
    知识点2@PreDestroy
    名称@PreDestroy
    类型方法注解
    位置方法上
    作用设置该方法为销毁方法
    属性

    小结

    1630033039358

    2.4 注解开发依赖注入

    Spring为了使用注解简化开发并没有提供构造函数注入setter注入对应的注解只提供了自动装配的注解实现。

    2.4.1 环境准备

    在学习之前把案例环境介绍下:

    • 创建一个Maven项目

    • pom.xml添加Spring的依赖

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
    • 添加一个配置类SpringConfig

      @Configuration
      @ComponentScan("com.java")
      public class SpringConfig {
      }
      
    • 添加BookDao、BookDaoImpl、BookService、BookServiceImpl类

      public interface BookDao {
          public void save();
      }
      @Repository
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      public interface BookService {
          public void save();
      }
      @Service
      public class BookServiceImpl implements BookService {
          private BookDao bookDao;
      	public void setBookDao(BookDao bookDao) {
              this.bookDao = bookDao;
          }
          public void save() {
              System.out.println("book service save ...");
              bookDao.save();
          }
      }
      
    • 创建运行类App

      public class App {
          public static void main(String[] args) {
              AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
              BookService bookService = ctx.getBean(BookService.class);
              bookService.save();
          }
      }
      

    最终创建好的项目结构如下:

    1630033604129

    环境准备好后运行后会发现有问题

    1630033710052

    出现问题的原因是在BookServiceImpl类中添加了BookDao的属性并提供了setter方法但是目前是没有提供配置注入BookDao的所以bookDao对象为Null,调用其save方法就会报控指针异常

    2.4.2 注解实现按照类型注入

    对于这个问题使用注解该如何解决?

    (1) 在BookServiceImpl类的bookDao属性上添加@Autowired注解

    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        private BookDao bookDao;
        
    //	  public void setBookDao(BookDao bookDao) {
    //        this.bookDao = bookDao;
    //    }
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    

    注意:

    • @Autowired可以写在属性上也可也写在setter方法上最简单的处理方式是写在属性上并将setter方法删除掉
    • 为什么setter方法可以删除呢?
      • 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
      • 普通反射只能获取public修饰的内容
      • 暴力反射除了获取public修饰的内容还可以获取private修改的内容
      • 所以此处无需提供setter方法

    (2)@Autowired是按照类型注入那么对应BookDao接口如果有多个实现类比如添加BookDaoImpl2

    @Repository
    public class BookDaoImpl2 implements BookDao {
        public void save() {
            System.out.println("book dao save ...2");
        }
    }
    

    这个时候再次运行App就会报错

    1630034272959

    此时按照类型注入就无法区分到底注入哪个对象解决方案:按照名称注入

    • 先给两个Dao类分别起个名称

      @Repository("bookDao")
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      @Repository("bookDao2")
      public class BookDaoImpl2 implements BookDao {
          public void save() {
              System.out.println("book dao save ...2" );
          }
      }
      

      此时就可以注入成功但是得思考个问题:

      • @Autowired是按照类型注入的给BookDao的两个实现起了名称它还是有两个bean对象为什么不报错?

      • @Autowired默认按照类型自动装配如果IOC容器中同类的Bean找到多个就按照变量名和Bean的名称匹配。因为变量名叫bookDao而容器中也有一个booDao所以可以成功注入。

      • 分析下面这种情况是否能完成注入呢?

        1630036236150

      • 不行因为按照类型会找到多个bean对象此时会按照bookDao名称去找因为IOC容器只有名称叫bookDao1bookDao2,所以找不到会报NoUniqueBeanDefinitionException

    2.4.3 注解实现按照名称注入

    当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致这个时候该如何解决就需要使用到@Qualifier来指定注入哪个名称的bean对象。

    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        @Qualifier("bookDao1")
        private BookDao bookDao;
        
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    

    @Qualifier注解后的值就是需要注入的bean的名称。

    注意:@Qualifier不能独立使用必须和@Autowired一起使用

    2.4.4 简单数据类型注入

    引用类型看完简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型下面在BookDaoImpl类中添加一个name属性用其进行简单类型注入

    @Repository("bookDao")
    public class BookDaoImpl implements BookDao {
        private String name;
        public void save() {
            System.out.println("book dao save ..." + name);
        }
    }
    

    数据类型换了对应的注解也要跟着换这次使用@Value注解将值写入注解的参数中就行了

    @Repository("bookDao")
    public class BookDaoImpl implements BookDao {
        @Value("java")
        private String name;
        public void save() {
            System.out.println("book dao save ..." + name);
        }
    }
    

    注意数据格式要匹配如将"abc"注入给int值这样程序就会报错。

    介绍完后会有一种感觉就是这个注解好像没什么用跟直接赋值是一个效果还没有直接赋值简单所以这个注解存在的意义是什么?

    2.4.5 注解读取properties配置文件

    @Value一般会被用在从properties配置文件中读取内容进行使用具体如何实现?

    步骤1resource下准备properties文件

    jdbc.properties

    name=java
    
    步骤2: 使用注解加载properties配置文件

    在配置类上添加@PropertySource注解

    @Configuration
    @ComponentScan("com.java")
    @PropertySource("jdbc.properties")
    public class SpringConfig {
    }
    
    
    步骤3使用@Value读取配置文件中的内容
    @Repository("bookDao")
    public class BookDaoImpl implements BookDao {
        @Value("${name}")
        private String name;
        public void save() {
            System.out.println("book dao save ..." + name);
        }
    }
    

    步骤4:运行程序

    运行App类查看运行结果说明配置文件中的内容已经被加载到

    1630084683663

    注意:

    • 如果读取的properties配置文件有多个可以使用@PropertySource的属性来指定多个

      @PropertySource({"jdbc.properties","xxx.properties"})
      
    • @PropertySource注解属性中不支持使用通配符*,运行会报错

      @PropertySource({"*.properties"})
      
    • @PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件

      @PropertySource({"classpath:jdbc.properties"})
      

    知识点1@Autowired

    名称@Autowired
    类型属性注解 或 方法注解了解 或 方法形参注解了解
    位置属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面
    作用为引用类型属性设置值
    属性requiredtrue/false定义该属性是否允许为null

    知识点2@Qualifier

    名称@Qualifier
    类型属性注解 或 方法注解了解
    位置属性定义上方 或 标准set方法上方 或 类set方法上方
    作用为引用类型属性指定注入的beanId
    属性value默认设置注入的beanId

    知识点3@Value

    名称@Value
    类型属性注解 或 方法注解了解
    位置属性定义上方 或 标准set方法上方 或 类set方法上方
    作用为 基本数据类型 或 字符串类型 属性设置值
    属性value默认要注入的属性值

    知识点4@PropertySource

    名称@PropertySource
    类型类注解
    位置类定义上方
    作用加载properties文件中的属性值
    属性value默认设置加载的properties文件对应的文件名或文件名组成的数组

    3IOC/DI注解开发管理第三方bean

    前面定义bean的时候都是在自己开发的类上面写个注解就完成了但如果是第三方的类这些类都是在jar包中我们没有办法在类上面添加注解这个时候该怎么办?

    遇到上述问题我们就需要有一种更加灵活的方式来定义bean,这种方式不能在原始代码上面书写注解一样能定义bean,这就用到了一个全新的注解==@Bean==。

    这个注解该如何使用呢?

    咱们把之前使用配置方式管理的数据源使用注解再来一遍通过这个案例来学习下@Bean的使用。

    3.1 环境准备

    学习@Bean注解之前先来准备环境:

    • 创建一个Maven项目

    • pom.xml添加Spring的依赖

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
    • 添加一个配置类SpringConfig

      @Configuration
      public class SpringConfig {
      }
      
    • 添加BookDao、BookDaoImpl类

      public interface BookDao {
          public void save();
      }
      @Repository
      public class BookDaoImpl implements BookDao {
          public void save() {
              System.out.println("book dao save ..." );
          }
      }
      
    • 创建运行类App

      public class App {
          public static void main(String[] args) {
              AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
          }
      }
      

    最终创建好的项目结构如下:

    1630122466404

    3.2 注解开发管理第三方bean

    在上述环境中完成对Druid数据源的管理具体的实现步骤为:

    步骤1:导入对应的jar包

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    

    步骤2:在配置类中添加一个方法

    注意该方法的返回值就是要创建的Bean对象类型

    @Configuration
    public class SpringConfig {
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    

    步骤3:在方法上添加@Bean注解

    @Bean注解的作用是将方法的返回值制作为Spring管理的一个bean对象

    @Configuration
    public class SpringConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    

    注意:不能使用DataSource ds = new DruidDataSource()

    因为DataSource接口中没有对应的setter方法来设置属性。

    步骤4:从IOC容器中获取对象并打印

    public class App {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            DataSource dataSource = ctx.getBean(DataSource.class);
            System.out.println(dataSource);
        }
    }
    

    至此使用@Bean来管理第三方bean的案例就已经完成。

    如果有多个bean要被Spring管理直接在配置类中多些几个方法方法上添加@Bean注解即可。

    ###3.3 引入外部配置类

    如果把所有的第三方bean都配置到Spring的配置类SpringConfig中虽然可以但是不利于代码阅读和分类管理所有我们就想能不能按照类别将这些bean配置到不同的配置类中?

    对于数据源的bean,我们新建一个JdbcConfig配置类并把数据源配置到该类下。

    public class JdbcConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    

    现在的问题是这个配置类如何能被Spring配置类加载到并创建DataSource对象在IOC容器中?

    针对这个问题有两个解决方案:

    3.3.1 使用包扫描引入

    步骤1:在Spring的配置类上添加包扫描
    @Configuration
    @ComponentScan("com.java.config")
    public class SpringConfig {
    	
    }
    
    步骤2:在JdbcConfig上添加配置注解

    JdbcConfig类要放入到com.java.config包下需要被Spring的配置类扫描到即可

    @Configuration
    public class JdbcConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    
    步骤3:运行程序

    依然能获取到bean对象并打印控制台。

    这种方式虽然能够扫描到但是不能很快的知晓都引入了哪些配置类所有这种方式不推荐使用。

    3.3.2 使用@Import引入

    方案一实现起来有点小复杂Spring早就想到了这一点于是又给我们提供了第二种方案。

    这种方案可以不用加@Configuration注解但是必须在Spring配置类上使用@Import注解手动引入需要加载的配置类

    步骤1:去除JdbcConfig类上的注解
    public class JdbcConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    
    步骤2:在Spring配置类中引入
    @Configuration
    //@ComponentScan("com.java.config")
    @Import({JdbcConfig.class})
    public class SpringConfig {
    	
    }
    

    注意:

    • 扫描注解可以移除

    • @Import参数需要的是一个数组可以引入多个配置类。

    • @Import注解在配置类中只能写一次下面的方式是不允许的

      @Configuration
      //@ComponentScan("com.java.config")
      @Import(JdbcConfig.class)
      @Import(Xxx.class)
      public class SpringConfig {
      	
      }
      
    步骤3:运行程序

    依然能获取到bean对象并打印控制台

    知识点1@Bean

    名称@Bean
    类型方法注解
    位置方法定义上方
    作用设置该方法的返回值作为spring管理的bean
    属性value默认定义bean的id

    知识点2@Import

    名称@Import
    类型类注解
    位置类定义上方
    作用导入配置类
    属性value默认定义导入的配置类类名
    当配置类有多个时使用数组格式一次性导入多个配置类

    3.4 注解开发实现为第三方bean注入资源

    在使用@Bean创建bean对象的时候如果方法在创建的过程中需要其他资源该怎么办?

    这些资源会有两大类分别是简单数据类型引用数据类型

    3.4.1 简单数据类型

    3.4.1.1 需求分析

    对于下面代码关于数据库的四要素不应该写死在代码中应该是从properties配置文件中读取。如何来优化下面的代码?

    public class JdbcConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    
    3.4.1.2 注入简单数据类型步骤
    步骤1:类中提供四个属性
    public class JdbcConfig {
        private String driver;
        private String url;
        private String userName;
        private String password;
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    
    步骤2:使用@Value注解引入值
    public class JdbcConfig {
        @Value("com.mysql.jdbc.Driver")
        private String driver;
        @Value("jdbc:mysql://localhost:3306/spring_db")
        private String url;
        @Value("root")
        private String userName;
        @Value("password")
        private String password;
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
    }
    
    扩展

    现在的数据库连接四要素还是写在代码中需要做的是将这些内容提

    取到jdbc.properties配置文件大家思考下该如何实现?

    1.resources目录下添加jdbc.properties

    2.配置文件中提供四个键值对分别是数据库的四要素

    3.使用@PropertySource加载jdbc.properties配置文件

    4.修改@Value注解属性的值将其修改为${key}key就是键值对中的键的值

    具体的实现就交由大家自行实现下。

    3.4.2 引用数据类型

    3.4.2.1 需求分析

    假设在构建DataSource对象的时候需要用到BookDao对象该如何把BookDao对象注入进方法内让其使用呢?

    public class JdbcConfig {
    	@Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
            ds.setUsername("root");
            ds.setPassword("root");
            return ds;
        }
    }
    
    3.4.2.2 注入引用数据类型步骤
    步骤1:在SpringConfig中扫描BookDao

    扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象

    @Configuration
    @ComponentScan("com.java.dao")
    @Import({JdbcConfig.class})
    public class SpringConfig {
    }
    
    步骤2:在JdbcConfig类的方法上添加参数
    @Bean
    public DataSource dataSource(BookDao bookDao){
        System.out.println(bookDao);
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
    

    引用类型注入只需要为bean定义方法设置形参即可容器会根据类型自动装配对象。

    步骤3:运行程序

    1630125475609

    4注解开发总结

    前面我们已经完成了XML配置和注解的开发实现至于两者之间的差异咱们放在一块去对比回顾下:

    1630134786448

    5Spring整合

    课程学习到这里已经对Spring有一个简单的认识了Spring有一个容器叫做IoC容器里面保存bean。在进行企业级开发的时候其实除了将自己写的类让Spring管理之外还有一部分重要的工作就是使用第三方的技术。前面已经讲了如何管理第三方bean了下面结合IoC和DI整合2个常用技术进一步加深对Spring的使用理解。

    5.1 Spring整合Mybatis思路分析

    5.1.1 环境准备

    在准备环境的过程中我们也来回顾下Mybatis开发的相关内容:

    步骤1:准备数据库表

    Mybatis是来操作数据库表所以先创建一个数据库及表

    create database spring_db character set utf8;
    use spring_db;
    create table tbl_account(
        id int primary key auto_increment,
        name varchar(35),
        money double
    );
    
    步骤2:创建项目导入jar包

    项目的pom.xml添加相关依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
    
    步骤3:根据表创建模型类
    public class Account implements Serializable {
    
        private Integer id;
        private String name;
        private Double money;
    	//setter...getter...toString...方法略    
    }
    
    步骤4:创建Dao接口
    public interface AccountDao {
    
        @Insert("insert into tbl_account(name,money)values(#{name},#{money})")
        void save(Account account);
    
        @Delete("delete from tbl_account where id = #{id} ")
        void delete(Integer id);
    
        @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
        void update(Account account);
    
        @Select("select * from tbl_account")
        List<Account> findAll();
    
        @Select("select * from tbl_account where id = #{id} ")
        Account findById(Integer id);
    }
    
    步骤5:创建Service接口和实现类
    public interface AccountService {
    
        void save(Account account);
    
        void delete(Integer id);
    
        void update(Account account);
    
        List<Account> findAll();
    
        Account findById(Integer id);
    
    }
    
    @Service
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
        public void save(Account account) {
            accountDao.save(account);
        }
    
        public void update(Account account){
            accountDao.update(account);
        }
    
        public void delete(Integer id) {
            accountDao.delete(id);
        }
    
        public Account findById(Integer id) {
            return accountDao.findById(id);
        }
    
        public List<Account> findAll() {
            return accountDao.findAll();
        }
    }
    
    步骤6:添加jdbc.properties文件

    resources目录下添加用于配置数据库连接四要素

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
    jdbc.username=root
    jdbc.password=root
    

    useSSL:关闭MySQL的SSL连接

    步骤7:添加Mybatis核心配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!--读取外部properties配置文件-->
        <properties resource="jdbc.properties"></properties>
        <!--别名扫描的包路径-->
        <typeAliases>
            <package name="com.java.domain"/>
        </typeAliases>
        <!--数据源-->
        <environments default="mysql">
            <environment id="mysql">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
        </environments>
        <!--映射文件扫描包路径-->
        <mappers>
            <package name="com.java.dao"></package>
        </mappers>
    </configuration>
    
    步骤8:编写应用程序
    public class App {
        public static void main(String[] args) throws IOException {
            // 1. 创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2. 加载SqlMapConfig.xml配置文件
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml.bak");
            // 3. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            // 4. 获取SqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 5. 执行SqlSession对象执行查询获取结果User
            AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
    
            Account ac = accountDao.findById(1);
            System.out.println(ac);
    
            // 6. 释放资源
            sqlSession.close();
        }
    }
    
    步骤9:运行程序

    1630136904087

    5.1.2 整合思路分析

    Mybatis的基础环境我们已经准备好了接下来就得分析下在上述的内容中哪些对象可以交给Spring来管理?

    • Mybatis程序核心对象分析

      1630137189480

      从图中可以获取到真正需要交给Spring管理的是SqlSessionFactory

    • 整合Mybatis就是将Mybatis用到的内容交给Spring管理分析下配置文件

      1630137388717

      说明:

      • 第一行读取外部properties配置文件Spring有提供具体的解决方案@PropertySource,需要交给Spring
      • 第二行起别名包扫描为SqlSessionFactory服务的需要交给Spring
      • 第三行主要用于做连接池Spring之前我们已经整合了Druid连接池这块也需要交给Spring
      • 前面三行一起都是为了创建SqlSession对象用的那么用Spring管理SqlSession对象吗?回忆下SqlSession是由SqlSessionFactory创建出来的所以只需要将SqlSessionFactory交给Spring管理即可。
      • 第四行是Mapper接口和映射文件[如果使用注解就没有该映射文件]这个是在获取到SqlSession以后执行具体操作的时候用所以它和SqlSessionFactory创建的时机都不在同一个时间可能需要单独管理。

    5.2 Spring整合Mybatis

    前面我们已经分析了Spring与Mybatis的整合大体需要做两件事

    第一件事是:Spring要管理MyBatis中的SqlSessionFactory

    第二件事是:Spring要管理Mapper接口的扫描

    具体该如何实现具体的步骤为:

    步骤1:项目中导入整合需要的jar包

    <dependency>
        <!--Spring操作数据库需要该jar包-->
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
        <!--
    		Spring与Mybatis整合的jar包
    		这个jar包mybatis在前面是Mybatis提供的
    	-->
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    

    步骤2:创建Spring的主配置类

    //配置类注解
    @Configuration
    //包扫描主要扫描的是项目中的AccountServiceImpl类
    @ComponentScan("com.java")
    public class SpringConfig {
    }
    
    

    步骤3:创建数据源的配置类

    在配置类中完成数据源的创建

    public class JdbcConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String userName;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
    }
    

    步骤4:主配置类中读properties并引入数据源配置类

    @Configuration
    @ComponentScan("com.java")
    @PropertySource("classpath:jdbc.properties")
    @Import(JdbcConfig.class)
    public class SpringConfig {
    }
    
    

    步骤5:创建Mybatis配置类并配置SqlSessionFactory

    public class MybatisConfig {
        //定义beanSqlSessionFactoryBean用于产生SqlSessionFactory对象
        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
            //设置模型类的别名扫描
            ssfb.setTypeAliasesPackage("com.java.domain");
            //设置数据源
            ssfb.setDataSource(dataSource);
            return ssfb;
        }
        //定义bean返回MapperScannerConfigurer对象
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("com.java.dao");
            return msc;
        }
    }
    

    说明:

    • 使用SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息

      1630138835057

      • SqlSessionFactoryBean是前面我们讲解FactoryBean的一个子类在该类中将SqlSessionFactory的创建进行了封装简化对象的创建我们只需要将其需要的内容设置即可。
      • 方法中有一个参数为dataSource,当前Spring容器中已经创建了Druid数据源类型刚好是DataSource类型此时在初始化SqlSessionFactoryBean这个对象的时候发现需要使用DataSource对象而容器中刚好有这么一个对象就自动加载了DruidDataSource对象。
    • 使用MapperScannerConfigurer加载Dao接口创建代理对象保存到IOC容器中

      1630138916939

      • 这个MapperScannerConfigurer对象也是MyBatis提供的专用于整合的jar包中的类用来处理原始配置文件中的mappers相关配置加载数据层的Mapper接口类
      • MapperScannerConfigurer有一个核心属性basePackage就是用来设置所扫描的包路径

    步骤6:主配置类中引入Mybatis配置类

    @Configuration
    @ComponentScan("com.java")
    @PropertySource("classpath:jdbc.properties")
    @Import({JdbcConfig.class,MybatisConfig.class})
    public class SpringConfig {
    }
    

    步骤7:编写运行类

    在运行类中从IOC容器中获取Service对象调用方法获取结果

    public class App2 {
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
    
            AccountService accountService = ctx.getBean(AccountService.class);
    
            Account ac = accountService.findById(1);
            System.out.println(ac);
        }
    }
    
    

    步骤8:运行程序

    1630139036627

    支持Spring与Mybatis的整合就已经完成了其中主要用到的两个类分别是:

    • SqlSessionFactoryBean
    • MapperScannerConfigurer

    5.3 Spring整合Junit

    整合Junit与整合Druid和MyBatis差异比较大为什么呢Junit是一个搞单元测试用的工具它不是我们程序的主体也不会参加最终程序的运行从作用上来说就和之前的东西不一样它不是做功能的看做是一个辅助工具就可以了。

    5.3.1 环境准备

    这块环境大家可以直接使用Spring与Mybatis整合的环境即可。当然也可以重新创建一个因为内容是一模一样所以我们直接来看下项目结构即可:

    1630139720273

    5.3.2 整合Junit步骤

    在上述环境的基础上我们来对Junit进行整合。

    步骤1:引入依赖

    pom.xml

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    
    步骤2:编写测试类

    在test\java下创建一个AccountServiceTest,这个名字任意

    //设置类运行器
    @RunWith(SpringJUnit4ClassRunner.class)
    //设置Spring环境对应的配置类
    @ContextConfiguration(classes = {SpringConfiguration.class}) //加载配置类
    //@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件
    public class AccountServiceTest {
        //支持自动装配注入bean
        @Autowired
        private AccountService accountService;
        @Test
        public void testFindById(){
            System.out.println(accountService.findById(1));
    
        }
        @Test
        public void testFindAll(){
            System.out.println(accountService.findAll());
        }
    }
    

    注意:

    • 单元测试如果测试的是注解配置类则使用@ContextConfiguration(classes = 配置类.class)
    • 单元测试如果测试的是配置文件则使用@ContextConfiguration(locations={配置文件名,...})
    • Junit运行后是基于Spring环境运行的所以Spring提供了一个专用的类运行器这个务必要设置这个类运行器就在Spring的测试专用包中提供的导入的坐标就是这个东西SpringJUnit4ClassRunner
    • 上面两个配置都是固定格式当需要测试哪个bean时使用自动装配加载对应的对象下面的工作就和以前做Junit单元测试完全一样了

    知识点1@RunWith

    名称@RunWith
    类型测试类注解
    位置测试类定义上方
    作用设置JUnit运行器
    属性value默认运行所使用的运行期

    知识点2@ContextConfiguration

    名称@ContextConfiguration
    类型测试类注解
    位置测试类定义上方
    作用设置JUnit加载的Spring核心配置
    属性classes核心配置类可以使用数组的格式设定加载多个配置类
    locations:配置文件可以使用数组的格式设定加载多个配置文件名称
  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: Spring