• Spring(二)




    一、基于注解的IOC和DI


    1) 准备工作


    创建Maven项目,导入依赖坐标

    <dependencies>
         <dependency>
             <groupId>org.springframeworkgroupId>
             <artifactId>spring-contextartifactId>
             <version>5.1.2.RELEASEversion>
         dependency>
         <dependency>
             <groupId>junitgroupId>
             <artifactId>junitartifactId>
             <version>4.12version>
         dependency>
     dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2) 编写代码,并注解配置


    UserDao接口

    package com.execise.dao;
    
    public interface UserDao {
        void add();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    UserDaoImpl实现类

    package com.execise.dao.impl;
    
    import com.execise.dao.UserDao;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Repository;
    
    @Component
    public class UserDaoImpl implements UserDao {
        public void add() {
            System.out.println("调用了UserDaoImpl的add方法~!~");
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    UserService接口

    package com.execise.service;
    
    public interface UserService {
        void add();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    UserServiceImpl实现类

    package com.execise.service.impl;
    
    import com.execise.dao.UserDao;
    import com.v.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /*
        需求:
            在UserServiceImpl里面调用UserDaoImpl的add方法
        分析:
            1. 把这两个类交给spring管理,让spring创建这两个类的对象
            2. 在UserServiceImpl里面注入UserDaoImpl 的对象
            3. 使用对象来调用方法
         步骤:
            1. 在UserServiceImpl和UserDaoImpl身上打注解 :  @Component
            2. 在UserServiceImpl里面定义属性,private UserDao userDao;
            3. 在属性身上打注解:  @AutoWired
            4. 在xml里面打开扫描的开关,这样spring才能知道哪些类要创建对象,里面的什么属性要注入!
     */
    @Component 
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserDao userDaoImpl;
    
        public void add() {
            System.out.println("调用了UserServiceImpl的add方法~!");
            userDaoImpl.add();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3) 开启组件扫描


    创建applicationContext.xml,注意引入的context名称空间

    
    <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 http://www.springframework.org/schema/context/spring-context.xsd">
    
    
        
        
        <context:component-scan base-package="com.execise"/>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4) 功能测试


    创建一个测试类,调用Service

    package com.execise.test;
    
    import com.execise.service.UserService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUserServiceImpl {
    
        @Test
        public void testAdd(){
    
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            UserService us = context.getBean(UserService.class);
    
            //3. 调用方法
            us.add();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    步骤小结

    1. 导入依赖

    2. 定义接口和实现类(dao 和 service)

    3. 在实现类上面打上注解 @Component

    4. 在属性上面打上注解@AutoWired

    5. 在applicationContext.xml里面打开扫描的开关


    注解使用详解


    开启组件扫描


    在Spring中,如果要使用注解开发,就需要在applicationContext.xml中开启组件扫描,配置如下:

    
    <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 http://www.springframework.org/schema/context/spring-context.xsd">
    
    
        
        
        <context:component-scan base-package="com.execise"/>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    声明bean的注解【IOC】


    注解说明
    @Component用在类上,相当于bean标签
    @Controller用在web层类上,配置一个bean(是@Component的衍生注解)
    @Service用在service层类上,配置一个bean(是@Component的衍生注解)
    @Repository用在dao层类上,配置一个bean(是@Component的衍生注解)

    @Component:类级别的一个注解,用于声明一个bean,使用不多

    • value属性:bean的唯一标识 (id值)。如果不配置,默认以首字母小写的类名为id

    @Controller, @Service, @Repository,作用和@Component完全一样,但更加的语义化,使用更多

    • @Controller:用于web层的bean

    • @Service:用于Service层的bean

    • @Repository:用于dao层的bean


    示例


    • UserDaoImpl类上使用注解@Repository
    @Repository("userDao")
    public class UserDaoImpl implements UserDao{
    }
    
    • 1
    • 2
    • 3
    • UserServiceImpl类上使用注解@Service
    @Service("userService")
    public class UserServiceImpl implements UserService{
    }
    
    • 1
    • 2
    • 3
    • UserController类上使用注解@Controller
    @Controller
    public class UserController{}
    
    • 1
    • 2

    配置bean的注解 【IOC】


    注解说明
    @Scope相当于bean标签的scope属性
    @PostConstruct相当于bean标签的init-method属性
    @PreDestroy相当于bean标签的destory-method属性

    配置bean的作用范围:

    • @Scope:配置bean的作用范围,相当于bean标签的scope属性。加在bean对象上

    • @Scope的常用值有:

    • singleton:单例的,容器中只有一个该bean对象

      • 何时创建:容器初始化时
      • 何时销毁:容器关闭时
    • prototype:多例的,每次获取该bean时,都会创建一个bean对象

      • 何时创建:获取bean对象时
      • 何时销毁:长时间不使用,垃圾回收
    @Scope("prototype")
    @Service("userService")
    public class UserServiceImpl implements UserService{
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置bean生命周期的方法

    • @PostConstruct是方法级别的注解,用于指定bean的初始化方法

    • @PreDestroy是方法级别的注解,用于指定bean的销毁方法

    package com.execise.service.impl;
    
    import com.execise.dao.UserDao;
    import com.execise.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    @Service("us")
    @Scope("prototype")
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserDao userDaoImpl;
    
        public void add() {
            System.out.println("调用了UserServiceImpl的add方法~!");
            userDaoImpl.add();
        }
    
        //=========================================
        //对象创建完毕,就执行这个方法
        @PostConstruct
        public void init(){
            System.out.println("调用了UserServiceImpl的init方法~!");
        }
    
        //对象销毁的时候,就执行这个方法! 只有单例才会走这个方法
        @PreDestroy
        public void destroy(){
            System.out.println("调用了UserServiceImpl的destroy方法~!");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    依赖注入的注解【DI】


    注解说明
    @Autowired相当于property标签的ref 注入对象
    @Qualifier结合@Autowired使用,用于根据名称(标识符)注入依赖
    @Resource相当于@Autowired + @Qualifier
    @Value相当于property标签的value ,注入普通 的属性

    注入bean对象

    @Autowired:用于byType(按照类型来找对象)注入bean对象,按照依赖(属性)的类型,从Spring容器中查找要注入的bean对象

    1. 如果找到一个,直接注入

    2. 如果找到多个,则以变量名为id,查找bean对象并注入

    3. 如果找不到,抛异常

    @Qualifier:是按id注入,但需要和@Autowired配合使用。

    @Resource:(是jdk提供的)用于注入bean对象(byName注入),相当于@Autowired + @Qualifier


    绝大多数情况下,只要使用@Autowired注解注入即可

    使用注解注入时,不需要set方法了


    UserDao

    package com.itehima.dao;
    
    public interface UserDao {
        void add();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    UserDao实现

    package com.execise.dao.impl;
    
    import com.execise.dao.UserDao;
    import org.springframework.stereotype.Component;
    
    @Repository
    public class UserDaoImpl implements UserDao {
        public void add() {
            System.out.println("调用了UserdaoImpl的add方法~!~");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    UserService

    package com.itehima.service;
    
    public interface UserService {
        void add();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    UserService实现

    
    package com.execise.service.impl;
    
    import com.execise.dao.UserDao;
    import com.execise.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.annotation.Resource;
    
    @Service("us02")
    public class UserServiceImpl02 implements UserService {
    
    
        @Autowired
        private UserDao userDaoImpl02;
    
        @Autowired
        @Qualifier("userDaoImpl02")
        private UserDao abc;
    
        @Resource(name = "userDaoImpl02")
        private UserDao cba;
    
        @Value("深圳")
        private String address;
    
        public void add() {
            System.out.println("调用了UserServiceImpl02的add方法~!" + address);
            //userDaoImpl02.add();
            //abc.add();
            cba.add();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    测试

    package com.execise.test;
    
    import com.execise.service.UserService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUserServiceImpl02 {
    
        @Test
        public void testAdd(){
    
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            UserService us = (UserService) context.getBean("us02");
    
    
            //3. 调用方法
            us.add();
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    注入普通值


    @Value:注入简单类型值,例如:基本数据类型和String

    @Service
    public class UserServiceImpl02 implements UserService{
        
        @Value("深圳")
        private String address;
        
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    小结


    在xml里要开启组件扫描

    <context:component-scan base-package="com.execise"/>
    
    • 1

    声明bean的注解(注册bean的注解) | IOC的注解

    • @Component("bean的名称"), 括号里面bean的名称就是id 值, 可以用在任何类上,注册bean对象

    • @Controller("bean名称"), @Service("bean名称"), @Repository("bean名称"),分别用于web层、service层、dao层的类上

    配置bean的注解

    • 如果要给一个bean设置作用范围:在bean上加注解@Scope("singleton/prototype")

    • 如果要给一个bean设置一个初始化方法:就在方法上加注解@PostConstruct

    • 如果要给一个bean设置一个销毁方法:就在方法上加注解@PreDestroy

    依赖注入的注解

    • @Autowired:byType注入,直接加在依赖项那个成员变量上

      • Spring会根据类型,从容器里查找bean并注入进来

      • 如果只找到一

      • 合的就会报错

    • @Autowired + @Qualifier("要注入的bean的名称"): 这种组合一般不怎么用,因为比较麻烦。

    • @Resource(name="要注入的bean的名称"):byName注入

    • @Value("要注入的简单值"):用于注入简单值

      • @Value("${properties里的key}"):把properties里指定key的值注入进来。前提条件是必须已经引入了properties文件

    二、整合Mybatis(XML)


    spring作为service层框架,对dao层和web层提供了很好的支持,整合Mybatis其实就是把mybatis的核心配置文件(SQLMapConfig.xml) 给去掉,并且把调用mybatis的代码简化,简化成注入对象,然后直接调用方法。


    创建数据库

    create database day32;
    use day32;
    
    create table account(
    	id int primary key auto_increment,
    	name varchar(40),
    	money int
    );
    
    insert into account(name,money) values('zs',1000);
    insert into account(name,money) values('ls',1000);
    insert into account(name,money) values('ww',1000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    创建Maven工程,添加依赖

    
    <dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
    
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.23version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.6version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>2.0.6version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
    
        
        
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>1.7.20version>
        dependency>
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-classicartifactId>
            <version>1.2.3version>
        dependency>
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-coreartifactId>
            <version>1.2.3version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    创建bean

    package com.execise.bean;
    
    import java.io.Serializable;
    
    public class Account implements Serializable {
        private Integer id;
        private String name;
        private Integer money;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getMoney() {
            return money;
        }
    
        public void setMoney(Integer money) {
            this.money = money;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", money=" + money +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    定义dao接口和映射文件


    接口

    package com.execise.dao;
    
    import com.execise.bean.Account;
    import java.util.List;
    
    public interface AccountDao {
    
        /**
         * 查询所有账户信息列表
         * @return 账户列表
         */
        List<Account> findAll();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    映射文件

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.execise.dao.AccountDao">
    
        <select id="findAll" resultType="Account">
            select * from account
        select>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    定义service接口和实现


    接口

    package com.execise.service;
    
    import com.execise.bean.Account;
    
    import java.util.List;
    
    public interface AccountService {
    
        /**
         * 查询所有账户信息列表
         * @return 账户列表
         */
        List<Account> findAll();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    实现

    package com.execise.service.impl;
    
    import com.execise.bean.Account;
    import com.execise.dao.AccountDao;
    import com.execise.service.AccountService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
        /*
        需求:
            在service里面调用dao的findAll方法。
        步骤:
            1. 不写mybatis的核心配置文件了,但是核心配置文件的内容还是需要有的。由spring来接管这个工作。
            2.  mybatis的核心配置文件里面包含两个部分的内容: 环境配置和映射文件配置
                2.1 环境配置及映射文件配置由 SqlSessionFactoryBean类来接管
                2.2 接口代理对象生成由MapperScannerConfigure类来接管
            3. 以上的两个类对象需要在applicationContext.xml中定义出来!
            4. 在service类上打注解: @Service
            5. 在service里面定义出来dao的属性,然后在属性上打注解 : @Autowired
        */
        @Override
        public List<Account> findAll() {
            System.out.println("调用了AccountService的findAll方法...");
            return accountDao.findAll();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    定义配置文件


    db.properties

    
    db.driverClass=com.mysql.jdbc.Driver
    db.url=jdbc:mysql://localhost:3306/day32
    db.username=root
    db.password=root
    
    • 1
    • 2
    • 3
    • 4
    • 5

    applicationContext.xml

    
    
    <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 http://www.springframework.org/schema/context/spring-context.xsd">
    
        
        <context:component-scan base-package="com.execise"/>
    
        
        <context:property-placeholder location="classpath:db.properties"/>
    
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${db.driverClass}"/>
            <property name="url" value="${db.url}"/>
            <property name="username" value="${db.username}"/>
            <property name="password" value="${db.password}"/>
        bean>
    
        
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            
            <property name="dataSource" ref="dataSource"/>
            
            <property name="typeAliasesPackage" value="com.execise.bean"/>
            
            
            
            
        bean>
    
        
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.execise.dao"/>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    单元测试

    package com.v.test;
    
    import com.execise.service.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAccountServiceImpl {
    
        @Test
        public void testFindAll(){
    
            //1. 创建工厂
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //2. 问工厂要对象
            AccountService accountService = context.getBean(AccountService.class);
    
            //3. 调用方法
            System.out.println(accountService.findAll());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    三、纯注解开发IOC和DI


    在上边的CURD练习中,仍然有部分配置需要使用applicationContext.xml,那么能不能使用注解替换掉所有的xml呢?Spring提供了一些新注解,可以达到这个目标。


    请注意:Spring提供的这部分新注解,并非为了完全代替掉XML,只是提供了另外一种配置方案


    注解说明
    @Configuration被此注解标记的类,是配置类 等同于applicationContext.xml
    @ComponentScan用在配置类上,开启注解扫描。使用basePackage属性指定扫描的包
    @PropertySource用在配置类上,加载properties文件。使用value属性指定properties文件路径
    @Import用在配置类上,引入子配置类。用value属性指定子配置类的Class
    @Bean用在配置类的方法上,把返回值声明为一个bean。用name/value属性指定bean的id

    注解详解


    导入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.23version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>2.0.6version>
        dependency>
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.6version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    @Configuration配置类


    @Configuration把一个Java类声明为核心配置类

    • 加上Java类上,这个Java类就成为了Spring的核心配置类,用于代替applicationContext.xml

    • @Component的衍生注解,所以:核心配置类也是bean,也会被spring管理起来,当然里边也可以注入依赖

    /*
        @Configuration:
            1. 表示这个类是一个核心配置类
            2. 它的作用等价于以前的applicationContext.xml
            3. @Configuration 是从@Component注解衍生出来的,所以这个类也会被spring管理起来(创建对象)
     */
    @Configuration
    public class AppConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    配置类上的注解


    @ComponentScan配置组件注解扫描

    • basePackages或者value属性:指定扫描的基本包

    • 等同于替代了applicationContext.xml里面的这句话

    
     <context:component-scan base-package="com.execise"/>
    
    • 1
    • 2

    @PropertySource用于加载properties文件

    • value属性:指定propertis文件的路径,从类加载路径里加载

    • 等同于替代了applicationContext.xml里面的这句话

    
    <context:property-placeholder location="classpath:db.properties"/>
    
    • 1
    • 2

    @Import用于导入其它配置类

    • Spring允许提供多个配置类(模块化配置),在核心配置类里加载其它配置类

    • 相当于xml中的标签


    核心配置类

    /*
        @Configuration:
            1. 表示这个类是一个核心配置类
            2. 它的作用等价于以前的applicationContext.xml
            3. @Configuration 是从@Component注解衍生出来的,所以这个类也会被spring管理起来(创建对象)
        @ComponentScan :
            1. 用来指定扫描包,等价于 
        @PropertyScource:
            1. 用来导入外部的properties文件,等价于
            2. 导入这个properties文件的时候,如果有错(1. 找不到这个文件,2.这个文件无法打开,)可以在
                名字的前面加上 classpath:
            3. 要想把properties里面的内容注入进来,就需要定义好对应的属性,然后使用@Value来注入值
                @Value("${KEY}")
         @Import:
            1. 可以用来导入子配置类
     */
    @Configuration
    @Import(AppConfig01.class) //导入子配置类
    public class AppConfig {
        @Value("${db.driverClass}")
        private String driverClass;
    
        @Value("${db.url}")
        private String url;
    
        @Value("${db.username}")
        private String username;
    
        @Value("${db.password}")
        private String password;
    
        public void show(){
            System.out.println("driverClass = " + driverClass);
            System.out.println("jdbcUrl = " + url);
            System.out.println("user = " + username);
            System.out.println("password = " + password);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    子配置类

    package com.execise.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.PropertySource;
    
    @ComponentScan("com.execise")
    @PropertySource("db.properties")
    public class AppConfig01 {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    @Bean声明bean


    1) @Bean定义bean


    @Bean注解:方法级别的注解

    • 作用: 方法会由spring调用,并且把方法返回值声明成为一个bean,作用相当于标签 , 这个方法的返回值将会被Spring管理起来。

    • @Bean注解可以写在方法上,这些方法可以写在核心配置类里面,也可以写在其他的组件类里面,但是一般会写在核心配置类里面。


    @Bean注解的属性:

    • value属性:bean的id。如果不设置,那么方法名就是bean的id
    
    @Configuration
    @ComponentScan("com.execise")
    public class AppConfig {
        
        /*
            @Bean
                1. 打在方法身上,spring会来调用这个方法
                2. spring会把这个方法的返回值管理起来,丢到spring的工厂里面去
                3. 可以在@Bean的value属性里面设置对象的id,如果不设置,那么将会使用方法的名字作为id值
         */
    
        //1. 把DataSource对象交给spring管理,使用方法名字作为id值
        @Bean
        public DataSource dataSource() throws PropertyVetoException {
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driverClass);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    
        // 2. 把DataSource对象交给spring管理,使用属性来指定id值
        @Bean("ds2")
        public DataSource dataSource2() throws PropertyVetoException {
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driverClass);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    
        /*
            3.使用@Bean注解标记的方法,方法内部需要用到spring工厂(容器)里面的某一个对象,怎么办?
                3.1 此时可以在方法的参数上,写上想要的对象参数即可
                    a. 其实它就是在方法参数的前面,隐藏着一个注解: @Autowired
                3.2 但是也要考虑出现极端的情况:如果在spring的容器里面,有多个对象满足这个参数的类型,咋办?
                    a. 搭配使用@Qualifier ,指定id值。
                    b. 投机取巧,把方法的参数名字,写成id的名字即可
    
         */
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean01(@Qualifier("dataSource") DataSource ds){
            System.out.println("ds===" + ds);
            SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
            sfb.setDataSource(ds);
            return sfb;
        }
        
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean02(DataSource dataSource){
            System.out.println("dataSource===" + dataSource);
            SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
            sfb.setDataSource(dataSource);
            return sfb;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    2) @Bean的依赖注入


    • @Bean注解的方法可以有任意参数,这些参数即是bean所需要的依赖,默认采用byType方式注入

    • 可以在方法参数上增加注解@Qualifier,用于byName注入


    3) 完整代码

    
    /*
        @Configuration:
            1. 表示这个类是一个核心配置类
            2. 它的作用等价于以前的applicationContext.xml
            3. @Configuration 是从@Component注解衍生出来的,所以这个类也会被spring管理起来(创建对象)
        @ComponentScan :
            1. 用来指定扫描包,等价于 
        @PropertyScource:
            1. 用来导入外部的properties文件,等价于
            2. 导入这个properties文件的时候,如果有错(1. 找不到这个文件,2.这个文件无法打开,)可以在
                名字的前面加上 classpath:
            3. 要想把properties里面的内容注入进来,就需要定义好对应的属性,然后使用@Value来注入值
                @Value("${KEY}")
         @Import:
            1. 可以用来导入子配置类
     */
    @Configuration
    //@ComponentScan("com.execise")
    //@PropertySource("db.properties")
    @Import(AppConfig01.class) //导入子配置类
    public class AppConfig {
        @Value("${db.driverClass}")
        private String driverClass;
    
        @Value("${db.url}")
        private String url;
    
        @Value("${db.username}")
        private String username;
    
        @Value("${db.password}")
        private String password;
    
        public void show(){
            System.out.println("driverClass = " + driverClass);
            System.out.println("jdbcUrl = " + url);
            System.out.println("user = " + username);
            System.out.println("password = " + password);
        }
    
        /*
            @Bean
                1. 打在方法身上,spring会来调用这个方法
                2. spring会把这个方法的返回值管理起来,丢到spring的工厂里面去
                3. 可以在@Bean的value属性里面设置对象的id,如果不设置,那么将会使用方法的名字作为id值
         */
    
        //1. 把DataSource对象交给spring管理,使用方法名字作为id值
        @Bean
        public DataSource dataSource() throws PropertyVetoException {
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driverClass);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    
        // 2. 把DataSource对象交给spring管理,使用属性来指定id值
        @Bean("ds2")
        public DataSource dataSource2() throws PropertyVetoException {
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driverClass);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    
        /*
            3.使用@Bean注解标记的方法,方法内部需要用到spring工厂(容器)里面的某一个对象,怎么办?
                3.1 此时可以在方法的参数上,写上想要的对象参数即可
                    a. 其实它就是在方法参数的前面,隐藏着一个注解: @Autowired
                3.2 但是也要考虑出现极端的情况:如果在spring的容器里面,有多个对象满足这个参数的类型,咋办?
                    a. 搭配使用@Qualifier ,指定id值。
                    b. 投机取巧,把方法的参数名字,写成id的名字即可
    
         */
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean01(@Qualifier("dataSource") DataSource ds){
            System.out.println("ds===" + ds);
            SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
            sfb.setDataSource(ds);
            return sfb;
        }
    
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean02(DataSource dataSource){
            System.out.println("dataSource===" + dataSource);
            SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
            sfb.setDataSource(dataSource);
            return sfb;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    小结

    • 配置类上要加注解@Configuration 变成核心配置类,主要是用来替代applicationContext.xml

    • 要开启组件扫描,在配置类上@ComponentScan("com.execise")

    • 如果要把jar包里的类注册成bean:

      • 在配置类里加方法,方法上加@Bean,会把方法返回值注册bean对象
    • 如果要引入外部的properties文件,在配置类上加@PropertySource("classpath:xxx.properties")

    • 引入模块配置类,在配置类上使用@Import(子配置类.class)

    • @Bean ,如果期望让spring来管理某个方法的返回值(注意: 这个返回值大多数都是对象,很少是一个普通的数据,比如:数字、字符串…)


    四、整合Mybatis(注解)


    导入依赖

    
    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <maven.compiler.source>1.8maven.compiler.source>
        <maven.compiler.target>1.8maven.compiler.target>
    properties>
    
    
    <dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
    
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.23version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.6version>
        dependency>
        
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>2.0.6version>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.1.2.RELEASEversion>
        dependency>
    
        
        
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>1.7.20version>
        dependency>
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-classicartifactId>
            <version>1.2.3version>
        dependency>
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-coreartifactId>
            <version>1.2.3version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    定义dao接口和映射文件


    接口

    package com.execise.dao;
    
    import com.execise.bean.Account;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    
    public interface AccountDao {
    
        /**
         * 查询所有账户信息列表
         * @return 账户列表
         */
        @Select("select * from account")
        List<Account> findAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    定义service接口和实现


    接口

    package com.execise.service;
    
    import com.execise.bean.Account;
    
    import java.util.List;
    
    public interface AccountService {
    
        /**
         * 查询所有账户信息列表
         * @return 账户列表
         */
        List<Account> findAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    实现

    package com.execise.service.impl;
    
    import com.execise.bean.Account;
    import com.execise.dao.AccountDao;
    import com.execise.service.AccountService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
        /*
        需求:
            在service里面调用dao的findAll方法。
        步骤:
            1. 不写mybatis的核心配置文件了,但是核心配置文件的内容还是需要有的。由spring来接管这个工作。
            2.  mybatis的核心配置文件里面包含两个部分的内容: 环境配置和映射文件配置
                2.1 环境配置由 SqlSessionFactoryBean类来接管
                2.2 映射文件配置由MapperScannerConfigure类来接管
            3. 以上的两个类需要在applicationContext.xml中定义出来!
            4. 在service类上打注解: @Service
            5. 在service里面定义出来dao的属性,然后在属性上打注解 : @Autowired
        */
        @Override
        public List<Account> findAll() {
            System.out.println("调用了AccountService的findAll方法...");
            return accountDao.findAll();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    定义配置文件


    db.properties

    
    db.driverClass=com.mysql.jdbc.Driver
    db.url=jdbc:mysql://localhost:3306/day32
    db.username=root
    db.password=root
    
    • 1
    • 2
    • 3
    • 4
    • 5

    AppConfig.java

    
    package com.execise.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.mybatis.spring.mapper.MapperScannerConfigurer;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    import javax.sql.DataSource;
    
    @Configuration
    @ComponentScan("com.execise")
    @PropertySource("classpath:db.properties")
    //@MapperScan("com.execise.dao")
    public class AppConfig {
    
        @Value("${db.driverClass}")
        private String driver;
        @Value("${db.url}")
        private String url;
        @Value("${db.username}")
        private String username;
        @Value("${db.password}")
        private String password;
    
    
        //1.创建数据源bean 交由Spring管理
        @Bean
        public DataSource dataSource(){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return  dataSource;
        }
    
        //2.创建SqlSessionFactory bean 交由Spring管理
        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSource);
            sqlSessionFactoryBean.setTypeAliasesPackage("com.execise.bean");
            return sqlSessionFactoryBean;
        }
    
        /*
            出现报错:
                ERROR com.alibaba.druid.pool.DruidDataSource - {dataSource-1} init error
                java.sql.SQLException: url not set
    
            错误排查【查看控制台日志】:
                  INFO org.springframework.context.annotation.ConfigurationClassPostProcessor -
                  Cannot enhance @Configuration bean definition 'appConfig' since its singleton instance has been created too early.
                  The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
    
            原因:
                由于MapperScannerConfigurer类实现了BeanDefinitionRegistryPostProcessor接口,这会让AppConfig类初始化,创建的时机太早,
                从而导致@Value注解失效,无法注入properties里面的数据
    
            解决:
                1.将这个方法变成静态方法,加上static
                2.可以将这个方法提取到另一个配置类里面去写,然后在这个核心配置类上面使用@Import注解导入进来
                3.也可以不在使用@Bean定义MapperScannerConfigurer的对象了,直接在配置类上添加一个注解@MapperScanner("com.execise.dao")
         */
    
        //3.创建MapperScannerConfigurer bean 扫描dao接口创建代理对象 交由Spring管理
        @Bean
        public static MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setBasePackage("com.execise.dao");
            return mapperScannerConfigurer;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    单元测试

    package com.execise.test;
    
    import com.execise.config.AppConfig;
    import com.execise.service.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    
    public class TestAccountServiceImpl {
    
        @Test
        public void testFindAll(){
    
            //1. 创建工厂
            ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
            //2. 问工厂要对象
            AccountService accountService = context.getBean(AccountService.class);
    
            //3. 调用方法
            System.out.println(accountService.findAll());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    五、Spring整合Junit


    在上边的CURD中,单元测试类里还需要我们自己去创建ApplicationContext,并自己去获取bean对象。Spring提供了整合Junit的方法,让单元测试更简洁方便。


    注解说明
    @RunWith用在测试类上,用于声明不再使用Junit,而是使用Spring提供的运行环境
    @ContextConfiguration用在测试类上,用于指定Spring配置类、或者Spring的配置文件

    Spring提供了单元测试的运行环境:SpringJunit4ClassRunner,配置到@RunWith注解上:

    @RunWith(SpringJunit4ClassRunner.class)


    要使用以上注解,需要导入jar包依赖:spring-testjunit

     <dependencies>
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-testartifactId>
                <version>5.1.2.RELEASEversion>
            dependency>
    
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-contextartifactId>
                <version>5.1.2.RELEASEversion>
            dependency>
    
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
            dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    使用示例


    步骤

    1. 在pom.xml文件中增加依赖:spring-testjunit

    2. 修改单元测试类

      1. 在单元测试类上增加注解:@RunWith(SpringJunit4ClassRunner.class)

        目的:使用Spring的单元测试运行器,替换Junit原生的运行器

      2. 在单元测试类上增加注解:@ContextConfiguration()

        目的:指定配置文件或配置类

      3. 在测试类里的依赖项上,直接使用@Autowired注入依赖


    实现


    在pom.xml文件中增加依赖:spring-testjunit

     <dependencies>
            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-contextartifactId>
                <version>5.1.2.RELEASEversion>
            dependency>
    
            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-testartifactId>
                <version>5.1.2.RELEASEversion>
            dependency>
    
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
            dependency>
    
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1. UserService接口
    package com.execise.service;
    
    public interface UserService {
        void add();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1. UserServiceImpl实现类
    package com.execise.service.impl;
    
    import com.execise.service.UserService;
    
    public class UserServiceImpl implements UserService {
        public void add() {
            System.out.println("调用了UserServiceImpl的add方法!~");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1. applicationContext.xml
    
    <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="us" class="com.execise.service.impl.UserServiceImpl"/>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1. 修改单元测试类
    package com.execise.test;
    
    import com.execise.service.UserService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    
    /*
        @RunWith
            1. 表示使用的单元测试的环境,不再是以前的Junit的测试环境,而是spring针对Junit提供的测试环境
            2. 这套spring提供的测试环境在背后会帮助我们创建工厂。
        @ContextConfiguration
            1. 告诉spring的测试环境,配置文件在哪里?
            2. classpath: 这是固定写法,表示要在类路径底下找配置文件。
     */
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class TestUserServiceImpl02 {
    
        //让spring把想要用到的对象给注入进来!
        // 这个注解是自动注入的意思,让spring把对象注入进来。明天讲!
        @Autowired
        private UserService us;
    
        @Test
        public void testAdd(){
    
            /*ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            UserService us = (UserService) context.getBean("us");
            */
            us.add();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    java学习之springcloud之服务注册与发现篇
    【springboot】13、Thymeleaf
    海滩的海鸥
    北大邹磊:图数据库中的子图匹配算法
    【漏洞复现】E-office文件包含漏洞
    故障振动频谱
    feign之间相互通信RequestInterceptor拦截器失效
    一次Kafka内存泄露排查经过
    Spring框架中用于注入构造函数参数的标签constructor-arg
    相信我,使用 Stream 真的可以让代码更优雅
  • 原文地址:https://blog.csdn.net/m0_67559541/article/details/126671109