【SSM开发框架】Spring之SpringIOC

笔记输出来源:拉勾教育Java就业急训营
如有侵权,私信立删

修改时间:2020年2月20日
作者:pp_x
邮箱:[email protected]

Spring概述

Spring 是什么

  • Spring是分层的 Java SE/EE应用** full-stack(全栈式) 轻量级开源框架**。
  • 提供了表现层 SpringMVC持久层 Spring JDBC Template以及 业务层 事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
  • 两大核心:
  • IOC(Inverse Of Control:控制反转)
  • AOP(Aspect Oriented Programming:面向切面编程)底层动态代理
    在这里插入图片描述

Spring发展历程

  • EJB
    • 1997 年,IBM提出了EJB 的思想
    • 1998 年,SUN制定开发标准规范 EJB1.0
    • 1999 年,EJB1.1 发布
    • 2001 年,EJB2.0 发布
    • 2003 年,EJB2.1 发布
    • 2006 年,EJB3.0 发布
  • Spring
    • Rod Johnson( Spring 之父)
    • 2002年编著《Expert one on one J2EE design and development》
      • 指出了JavaEE和EJB组件框架中的存在的一些主要缺陷;提出普通java类依赖注入更为简单的解决方案。
    • 2004年编著《Expert one-on-one J2EE Development without EJB》
      • 阐述了JavaEE开发时不使用EJB的解决方式(Spring 雏形)
      • 同年4月spring1.0诞生
    • 2006年10月,发布 Spring2.0
    • 2009年12月,发布 Spring3.0
    • 2013年12月,发布 Spring4.0
    • 2017年9月, 发布最新 Spring5.0 通用版(GA)

Spring优势

  • 方便解耦,简化开发
    • Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理
    • 什么是耦合度?对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。要尽量解耦
  • AOP编程的支持
    • Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能
  • 声明式事务的支持
    • 通过配置完成事务的管理,无需手动编程
  • 方便测试,降低JavaEE API的使用
    • Spring对Junit4支持,可以使用注解测试
  • 方便集成各种优秀框架
    • 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
      在这里插入图片描述

Spring体系结构

在这里插入图片描述

SpringIOC

IOC概述

  • 控制反转(Inverse Of Control)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序
    • 控制:在java中指的是对象的控制权限(创建、销毁)
    • 反转:指的是对象控制权由原来由开发者在类中手动控制反转到由Spring容器控制
  • 栗子:
    • 传统方式:之前我们需要一个userDao实例,需要开发者自己手动创建 new UserDao()
    • IOC方式:现在我们需要一个userDao实例,直接从spring的IOC容器获得,对象的创建权交给了spring控制
      在这里插入图片描述

自定义IOC容器

需求:实现service层与dao层代码解耦合

传统方式

  • dao层

public interface IUserDao {
    
    
    public void save();
}


public class UserDaoImpl implements IUserDao {
    
    
    public void save() {
    
    
        System.out.println("保存成功了...");
    }

}

  • service层
public interface IUserService {
    
    
    public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}


public class UserServiceImpl implements IUserService {
    
    
    private IUserDao userDao;
    public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    
    
        userDao = new UserDaoImpl();

        userDao.save();
    }
}
  • 测试
public class SpringTest {
    
    
    @Test
    public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    
    
        IUserService userService = new UserServiceImpl();
        userService.save();
    }
}

传统方式的问题

  • 每一个Service实现类都要new一个DaoImpl,存在编译期依赖,耦合重

解决方法:反射

  • 使用反射的方法避免使用new关键字来创建对象,达到解耦作用
  • 修改后的service层
public class UserServiceImpl implements IUserService {
    
    
    private IUserDao userDao;
    public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    
    
        //调用dao层方法  传统方式 存在编译器依赖
        //userDao = new UserDaoImpl();
        //反射
        userDao= (IUserDao)Class.forName("com.lagou.dao.impl.UserDaoImpl").newInstance();

        userDao.save();
    }
}

反射存在的问题

  • Class.forName("com.lagou.dao.impl.UserDaoImpl")中存在硬编码问题

采用IOC容器

  • 主要思想:配置文件解决硬编码,解析器解析配置文件,反射创建对象存入map集合
  • 步骤分析
    • 准备一个配置文件bean.xml
    • 编写一个工厂工具类,工厂类中使用dom4j来解析配置文件,获取到类的全路径
    • 使用反射生成对应类的实例对象,存到map中(IOC容器)
  • bean.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<!-- id:标识   class:村的就是要生成类的全路径   -->
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
</beans>
  • 修改后的service
public class UserServiceImpl implements IUserService {
    
    
    private IUserDao userDao;
    public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    
    
        //调用dao层方法  传统方式 存在编译器依赖
        //userDao = new UserDaoImpl();
        //反射
        //userDao= (IUserDao)Class.forName("com.lagou.dao.impl.UserDaoImpl").newInstance();
        //ioc容器
        IUserDao userDao = (IUserDao)BeanFactory.getBean("userDao");
        userDao.save();
    }
}

Spring相关API

在这里插入图片描述

BeanFactory

  • BeanFactoryIOC 容器的核心接口,它定义了IOC的基本功能
  • 特点:在第一次调用getBean()方法时,创建指定对象的实例
public void test2(){
    
    
        //核心接口 不会创建Bean对象存到容器中
        BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //getBean的时候才真正创建bean对象
        UserDao userDao = (UserDao) xmlBeanFactory.getBean("userDao");
        //调用方法
        userDao.save();
    }

ApplicationContext

  • 代表应用上下文对象,可以获得spring中IOC容器的Bean对象
  • 特点:在spring容器启动时,加载并创建所有对象的实例
public void test1(){
    
    
        //获取到了spring上下文对象  借助上下文对象可以获取到IOC容器的bean对象  加载同时创建了bean对象存在容器中
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用上下文对象从IOC容器中获取对应的bean
        //1.beanid在容器中找对应的bean对象
        //UserDao userDao = (UserDao)classPathXmlApplicationContext.getBean("userDao");
        //2.根据类型在容器中进行查询  如果查询到多个则报错
        //UserDao userDao = classPathXmlApplicationContext.getBean(UserDao.class);
        //3.根据类型和beanId同时查找
        UserDao userDao = classPathXmlApplicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }

ApplicationContext常用实现类

  • ClassPathXmlApplicationContext:它是从类的根路径下加载配置文件 推荐使用这种。
  • FileSystemXmlApplicationContext:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
public void test3(){
    
    
        ApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\Lagou\\Code\\spring\\spring_quickstart\\src\\main\\resources\\applicationContext.xml");
        UserDao userDao = (UserDao) fileSystemXmlApplicationContext.getBean("userDao");
        userDao.save();
    }
  • AnnotationConfigApplicationContext:当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解

ApplicationContext常用方法

  • Object getBean(String name):根据Bean的id从容器中获得Bean实例,返回是Object,需要强转
  • <T> T getBean(Class<T> requiredType):根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错
  • <T> T getBean(String name,Class<T> requiredType):根据Bean的id和类型获得Bean实例,解决容器中相同类型Bean有多个情况

Spring配置文件

Bean标签的基本配置

  • <bean id="" class=""></bean>
  • 用于配置对象交由Spring来创建。
  • 基本属性:
    • id:Bean实例在Spring容器中的唯一标识
    • class:Bean的全限定名
  • 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功

Bean标签范围配置

<bean id="" class="" scope=""></bean>

  • scope取值范围
取值范围 说明
singleton 默认值,单例的
prototype 多例的
request WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
session WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
global session WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession 相当于 session
  • 当scope的取值为singleton
    • Bean的实例化个数:1个
    • Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
    • Bean的生命周期:
      • 对象创建当应用加载,创建容器时,对象就被创建了
      • 对象运行:只要容器在,对象一直活着
      • 对象销毁:当应用卸载,销毁容器时,对象就被销毁
  • 当scope的取值为prototype
    • Bean的实例化个数:多个
    • Bean的实例化时机:当调用getBean()方法时实例化Bean
    • Bean的生命周期:
      • 对象创建当使用对象时,创建新的对象实例
      • 对象运行:只要对象在使用中,就一直活着
      • 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

Bean生命周期配置

<bean id="" class="" scope="" init-method="" destroy-method=""></bean>

  • init-method:指定类中的初始化方法名称
  • destroy-method:指定类中销毁方法名称
 public void init(){
    
    
        System.out.println("初始化方法执行了");

    }
    public void destory(){
    
    
        System.out.println("销毁方法执行了");
    }
 <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl" scope="singleton" init-method="init" destroy-method="destory"></bean>

Bean实例化的三种方式

  • 无参构造方法实例化
  • 工厂静态方法实例化
  • 工厂普通方法实例化

无参构造方法实例化

  • 会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>

工厂静态方法实例化

  • 应用场景
  • 依赖的jar包中有个A类,A类中有个静态方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
public class StaticFactoryBean {
    
     
	public static UserDao createUserDao(){
    
     
		return new UserDaoImpl(); 
	} 
}
<bean id="userDao" class="com.lagou.factory.StaticFactoryBean" factory-method="createUserDao" />

工厂普通方法实例化

  • 依赖的jar包中有个A类,A类中有个普通方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
public class DynamicFactoryBean {
    
     
	public UserDao createUserDao(){
    
     
		return new UserDaoImpl(); 
	} 
}
<bean id="dynamicFactoryBean" class="com.lagou.factory.DynamicFactoryBean"/> <bean id="userDao" factory-bean="dynamicFactoryBean" factory- method="createUserDao"/

Bean依赖注入概述

  • 依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
  • 在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
  • 这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是通过框架把持久层对象传入业务层,而不用我们自己去获取。

Bean依赖注入方法

构造方法

  • 在UserServiceImpl中创建有参构造
public class UserServiceImpl implements UserService {
    
     
	private UserDao userDao; 
	public UserServiceImpl(UserDao userDao) {
    
     
	this.userDao = userDao; 
}
@Override 
public void save() {
    
     
	userDao.save(); 
	} 
}
  • 配置Spring容器调用有参构造时进行注入
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
<!-- 有参构造实现依赖注入
                需要添加constructor-arg来指定有参构造
                    index="0"代表从第一个参数开始
                    type="com.lagou.dao.UserDao" 代表传入参数的类型
                    ref:引入的实例
                    name:与有参构造种形参名保持一致
                -->
 <constructor-arg index="0" type="com.lagou.dao.UserDao" ref="userDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>

Set方法

  • 在UserServiceImpl中创建set方法
public class UserServiceImpl implements UserService {
    
     
	private UserDao userDao; 
	public void setUserDao(UserDao userDao) {
    
     
	this.userDao = userDao; 
}
@Override public void save() {
    
     
	userDao.save(); 
	} 
}
  • 配置Spring容器调用set方法进行注入
 <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
         <!-- set实现依赖注入
               ref:指定传入的实参
               value:传入基本类型
               -->
 <property name="userDao" ref="userDao"></property>
</bean>

P命名空间注入

  • P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
  • 首先,需要引入P命名空间
xmlns:p="http://www.springframework.org/schema/p"
  • 其次,需要修改注入方式:
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/> 
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>

Bean依赖注入的数据类型

  1. 普通数据类型
  2. 引用数据类型
  3. 集合数据类型
  • 由于上部分代码都是引用类型,以下仅展示普通数据类型和集合数据类型
<!--  注入类型的测试  -->
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
 <!-- 普通数据类型的注入       -->
        <property name="username" value="柳潇"></property>
        <property name="age" value="18"></property>
<!-- 集合数据类型的注入-->
        <!--         list注入-->
        <property name="list">
            <list>
                <value>aaa</value>
                <ref bean="user"></ref>
            </list>
        </property>
        <!--         set注入-->
        <property name="set">
            <list>
                <value>bbb</value>
                <ref bean="user"></ref>
            </list>
        </property>
        <!--         数组注入-->
        <property name="array">
            <list>
                <value>ccc</value>
                <ref bean="user"></ref>
            </list>
        </property>
        <!--         map注入-->
        <property name="map">
            <map>
                <entry key="k1" value="ddd"></entry>
                <entry key="k2" value-ref="user"></entry>
            </map>
        </property>
        <!--         properties注入-->
        <property name="properties">
            <props>
                <prop key="k1">v1</prop>
                <prop key="k2">v2</prop>
            </props>
        </property>
    </bean>

配置文件模块化

  • 实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,也就是所谓的配置文件模块化
  • 并列的多个配置文件
ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");
  • 主从配置文件 在配置文件中编写
<import resource="applicationContext-xxx.xml"/>
  • 注意
    • 同一个xml中不能出现相同名称的bean,如果出现会报错
    • 多个xml如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean

小结

  • <bean>标签:创建对象并放到spring的IOC容器
    • id属性:在容器中Bean实例的唯一标识,不允许重复
    • class属性:要实例化的Bean的全限定名
    • scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
  • <constructor-arg>标签:属性注入
    • name属性:属性名称
    • value属性:注入的普通属性值
    • ref属性:注入的对象引用值
  • <property>标签:属性注入
    • name属性:属性名称
    • value属性:注入的普通属性值
    • ref属性:注入的对象引用值
    • <list>
    • <set>
    • <array>
    • <map>
    • <props>
  • <import>标签:导入其他的Spring的分文件

IOC整合Dbutils

  • dao层实现类
public class AccountDaoImpl implements AccountDao {
    
    

    private QueryRunner queryRunner;

    public void setQueryRunner(QueryRunner queryRunner) {
    
    
        this.queryRunner = queryRunner;
    }

    public List<Account> findAll() {
    
    
        List<Account> list = null;
        //编写sql
        String sql = "select * from account";
        try {
    
    
            list = queryRunner.query(sql, new BeanListHandler<Account>(Account.class));
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        return list;
    }

    public Account findById(int id) {
    
    
        Account query = null;
        //编写sql
        String sql = "select * from account where id = ?";
        try {
    
    
            query = queryRunner.query(sql, new BeanHandler<Account>(Account.class),id);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        return query;
    }

    public void save(Account account) {
    
    
        String sql = "insert into account values(null,?,?)";
        try {
    
    
            queryRunner.update(sql, account.getName(), account.getMoney());
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void update(Account account) {
    
    
        String sql  = "update account set name = ? , money = ? where id = ?";
        try {
    
    
            queryRunner.update(sql,account.getName(),account.getMoney(),account.getId());
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void delete(int id) {
    
    
        String sql = "delete from account where id = ?";
        try {
    
    
            queryRunner.update(sql,id);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }
}

  • service层实现类
public class AccountServiceImpl implements AccountService {
    
    
    @Autowired //根据类型进行注入 相当于<property>
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
    
    
        this.accountDao = accountDao;
    }

    public List<Account> findAll() {
    
    
        return accountDao.findAll();
    }

    public Account findById(int id) {
    
    
        return accountDao.findById(id);
    }

    public void save(Account account) {
    
    
        accountDao.save(account);
    }

    public void update(Account account) {
    
    
        accountDao.update(account);
    }

    public void delete(int id) {
    
    
        accountDao.delete(id);
    }
}
  • xml配置文件
<!--    引入jdbc.properties
        cla	sspath:  代表找文件时会定位到当前项目编译过后的classpath目录下查找
-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--  dataSource  -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
     </bean>
<!-- QueryRunner   -->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<!--        ds是queryrunner有参构造的参数名-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
<!-- AccountDao   -->
    <bean id="accountDao" class="com.lagou.dao.impl.AccountDaoImpl">
    <property name="queryRunner" ref="queryRunner"/>
    </bean>
<!--    AcountService-->
    <bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
  • 测试
public class AccountServiceTest {
    
    
    private ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    private AccountService accountService = (AccountService) classPathXmlApplicationContext.getBean("accountService");
    //测试添加
    @Test
    public void testSave(){
    
    

        Account account = new Account();
        account.setName("ppx");
        account.setMoney(8888d);
        accountService.save(account);
    }
    //测试根据id进行查询
    @Test
    public void testFindById(){
    
    
        Account accountServiceById = accountService.findById(1);
        System.out.println(accountServiceById);
    }
    //查询所有的信息
    @Test
    public void testFindAll(){
    
    
        List<Account> all = accountService.findAll();
        for (Account account : all) {
    
    
            System.out.println(account);
        }
    }
    //修改
    @Test
    public void testUpdate(){
    
    
        Account account = new Account();
        account.setId(3);
        account.setName("xiaogege");
        account.setMoney(1000d);
        accountService.update(account);
    }
}
  • Spring容器加载properties文件
    • <context:property-placeholder location="xx.properties"/>
    • <property name="" value="${key}"/>

Spring注解开发

常用注解

  • Spring常用注解主要是替代 <bean> 的配置
注解 功能
@Component 使用在类上用于实例化Bean
@Controller 使用在web层类上用于实例化Bean
@Service 使用在service层类上用于实例化Bean
@Repository 使用在dao层类上用于实例化Bean
@Autowired 使用在字段上用于根据类型依赖注入
@Qualifier 结合@Autowired一起使用,根据名称进行依赖注入
@Resource 相当于@Autowired+@Qualifier,按照名称进行注入
@Value 注入普通属性
@Scope 标注Bean的作用范围
@PostConstruct 使用在方法上标注该方法是Bean的初始化方法
@PreDestroy 使用在方法上标注该方法是Bean的销毁方法
  • @Repository 如果没有写value属性值,Bean的id为:类名首字母小写
  • @Autowired按类型匹配,如果没有设置@Qualifier,默认按变量名匹配,如果匹配到多个类型相同的则报错
  • 注意JDK11以后完全移除了javax扩展导致不能使用@resource注解
  • 需要引入依赖
<dependency> 
	<groupId>javax.annotation</groupId> 
	<artifactId>javax.annotation-api</artifactId> 
	<version>1.3.2</version> 
</dependency>
  • 注意:使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
<!--注解的组件扫描--> 
<context:component-scan base-package="com.lagou"></context:component-scan>

Spring新注解

  • 使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
    • 非自定义的Bean的配置:<bean>
    • 加载properties文件的配置:<context:property-placeholder>
    • 组件扫描的配置:<context:component-scan>
    • 引入其他文件:<import>
注解 功能
@Configuration 用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解
@Bean 使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource 用于加载properties 文件中的配置
@ComponentScan 用于指定Spring 在初始化容器时要扫描的包
@Import 用于导入其他配置类

注解完全整合Dbutils

  • dao层
@Repository
public class AccountDaoImpl implements AccountDao {
    
    
    @Autowired//使用注解后 set方法不需要
    private QueryRunner queryRunner;
    public List<Account> findAll() {
    
    
        List<Account> list = null;
        //编写sql
        String sql = "select * from account";
        try {
    
    
            list = queryRunner.query(sql, new BeanListHandler<Account>(Account.class));
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        return list;
    }

    public Account findById(int id) {
    
    
        Account query = null;
        //编写sql
        String sql = "select * from account where id = ?";
        try {
    
    
            query = queryRunner.query(sql, new BeanHandler<Account>(Account.class),id);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        return query;
    }

    public void save(Account account) {
    
    
        String sql = "insert into account values(null,?,?)";
        try {
    
    
            queryRunner.update(sql, account.getName(), account.getMoney());
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void update(Account account) {
    
    
        String sql  = "update account set name = ? , money = ? where id = ?";
        try {
    
    
            queryRunner.update(sql,account.getName(),account.getMoney(),account.getId());
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void delete(int id) {
    
    
        String sql = "delete from account where id = ?";
        try {
    
    
            queryRunner.update(sql,id);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }
}
  • service层
@Service("accountService")//相当于配置了Bean标签的Class属性   手动配置id属性
@Scope("singleton")
public class AccountServiceImpl implements AccountService {
    
    
    @Autowired //根据类型进行注入 相当于<property>
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
    
    
        this.accountDao = accountDao;
    }

    public List<Account> findAll() {
    
    
        return accountDao.findAll();
    }

    public Account findById(int id) {
    
    
        return accountDao.findById(id);
    }

    public void save(Account account) {
    
    
        accountDao.save(account);
    }

    public void update(Account account) {
    
    
        accountDao.update(account);
    }

    public void delete(int id) {
    
    
        accountDao.delete(id);
    }
}
  • 核心配置类
@Configuration//表示该类是核心配置类
@ComponentScan("com.lagou")//标识扫描该包及子包下的注解
@Import(DataSourceConfig.class)
public class SpringConfig {
    
    



    @Bean("queryRunner")
    //此处的@AutoWired代表有参构造的依赖注入
    public QueryRunner getQueryRunner(@Autowired DataSource dataSource){
    
    
        QueryRunner queryRunner = new QueryRunner(dataSource);
        return queryRunner;
    }
}

  • 数据配置类
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
    
    
    @Value("${jdbc.driverClassName}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    @Bean("dataSource")
    //会将该方法的返回值存到ioc容器中
    //如果不另起一个名字  则以方法名为key值
    public DataSource getDataSource(){
    
    
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}
  • 测试类
public class AccountServiceTest {
    
    
    //纯注解形式
    //使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    AccountService accountService = (AccountService) annotationConfigApplicationContext.getBean("accountService");
    //测试添加
    @Test
    public void testSave(){
    
    

        Account account = new Account();
        account.setName("ppx");
        account.setMoney(8888d);
        accountService.save(account);
    }
    //测试根据id进行查询
    @Test
    public void testFindById(){
    
    
        Account accountServiceById = accountService.findById(1);
        System.out.println(accountServiceById);
    }
    //查询所有的信息
    @Test
    public void testFindAll(){
    
    
        List<Account> all = accountService.findAll();
        for (Account account : all) {
    
    
            System.out.println(account);
        }
    }
    //修改
    @Test
    public void testUpdate(){
    
    
        Account account = new Account();
        account.setId(3);
        account.setName("xiaogege");
        account.setMoney(1000d);
        accountService.update(account);
    }
}

Spring整合Junit

普通Junit测试问题

  • 在普通的测试类中,需要开发者手动加载配置文件并创建Spring容器,然后通过Spring相关API获得Bean实例;如果不这么做,那么无法从容器中获得对象。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); 
AccountService accountService = applicationContext.getBean(AccountService.class);

Spring整合Junit

  • 步骤
  1. 导入spring集成Junit的坐标
  2. 使用@Runwith注解替换原来的运行器
  3. 使用@ContextConfiguration指定配置文件或配置类
  4. 使用@Autowired注入需要测试的对象
  5. 创建测试方法进行测试
  • 导入spring集成Junit的坐标
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上--> 
<dependency> 
	<groupId>org.springframework</groupId> 
	<artifactId>spring-test</artifactId> 
	<version>5.1.5.RELEASE</version> 
</dependency> 
<dependency> 
	<groupId>junit</groupId> 
	<artifactId>junit</artifactId> 
	<version>4.12</version> 
	<scope>test</scope> 
</dependency>
  • 使用@Runwith注解替换原来的运行器
@RunWith(SpringJUnit4ClassRunner.class) 
public class SpringJunitTest {
    
     
}
  • 使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"}) 加载spring 核心配置文件
@ContextConfiguration(classes = {
    
    SpringConfig.class}) // 加载spring核心配置类
public class SpringJunitTest {
    
     
}
  • 使用@Autowired注入需要测试的对象
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = {
    
    SpringConfig.class}) 
public class SpringJunitTest {
    
     
	@Autowired
	private AccountService accountService; 
}
  • 测试
@RunWith(SpringJUnit4ClassRunner.class) 
//@ContextConfiguration({"classpath:applicationContext.xml"})//配置文件
@ContextConfiguration(classes = {
    
    SpringConfig.class}) //配置类
public class SpringJunitTest {
    
     
	@Autowired private AccountService accountService; 
	//测试查询 
	@Test 
	public void testFindById() {
    
     
	Account account = accountService.findById(3); 
	System.out.println(account); 
	} 
}

猜你喜欢

转载自blog.csdn.net/weixin_46303867/article/details/113853603