Spring5笔记总结

<!doctype html>Spring5笔记css

 

Spring简介等(了解)

Spring简介

  • Spring是一个开发源代码的设计层面的框架,塔解决的是业务逻辑层和其余各层的松耦合问题, 下降耦合度,解耦 ,
  • 所以它将面向对象接口的编程思想贯穿整个系统
  • spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson建立,简单来讲,Spring是一个分层的JavaSe/EE full-stack(一站式)轻量级开源框架
  • 它是为了解决企业应用开发的复杂性而建立的。框架的主要优点之一就是其分层架构, 分层架构容许使用者选择使用哪个组件,同时为J2EE应用程序开发提供集成的框架。
  • Spring的核心是控制反转(lOC) 和面向切面(AOP) 。简单来讲,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
  • 以Ioc(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切片编程)为内核,使用简单的JavaBean来完成之前只能由EJB(Enterprise Java Beans)完成的工做,取代了臃肿、低效的EJB。

image-20200728140341478

  1. Spring是一个轻量级的开源的javaee框架html

    • 轻量级==大小很小,jar不多,不依赖其余组件,本身能够单独使用
    • 开源==免费
    • 框架==开发更加方便,代码更加简洁
  2. Spring目的:能够解决企业应用开发的复杂性java

  3. String组成部分:核心部分node

    1. IOC --> 反转控制,new ioc把建立对象过程交给Spring进行管理
    2. AOP --> 面向切面,扩展功能,不修改源代码进行功能加强

    Spring优势

    1. 方便解耦,简化开发,Spring就是一个大工厂,能够将全部对象建立和依赖关系维护,交给Spring, IOC的做用
    2. 声明式事务的支持,只须要经过配置就能够完成对事务的管理,而无需手动编程
    3. AOP编程支持 , Spring提供面向切面编程,能够方便的实现对程序进行权限拦截,运行监控等功能 (对某个方法加强,代理设计模式,装饰设计模式)
    4. 方便程序的测试,Spring对Junit4支持,能够经过注解方便的测试Spring的程序
    5. 方便集成各类优秀的框架,Spring不排除各类优秀的开源框架,其内部提供了对各类优秀的框架(如:Struts2 Hibernate ,Mybaits ,Quartz等)的直接支持
    6. 下降JavaEEAPI的使用难度 ,Spring对JavaEE开发中很是难用的一些API(JDBC,javaMail,远程调用等),都提供了封装,使这些API应用难度大大下降

总结一句话:Spring就是一个轻量级的数据反转(IOC)和面向切面编程(AOP)的框架mysql

组成

image-20200725140925736

扩展

  • 在Spring的官网有这个介绍:现代化的Java开发!说白了就是基于Spring的开发

image-20200725141003951

  • Spring bootweb

    • 一个快速开发的脚手架,
    • 基于SpringBoot快速的开发单个微服务
    • 约定大于配置!
  • Spring cloudspring

    • SpringCloud是基于SpringBoot实现的

由于使用的人多,大多数都在使用SpringBoot进行快速开发,学习SpringBoot的前提,须要彻底掌握Spring及SpringMVC!承上启下的做用!sql

弊端:发展了过久以后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!”数据库

Spring的IOC核心技术(掌握)

IOC的概念

什么是IOC?

  • IOC -- Inverse of Control,控制反转,将对象的建立权力反转给Spring框架
  • 控制反转(INversion of Control,缩写IOC) ,是面向对象编程中的一种设计原则,能够用来减低计算机代码之间的耦合度
  • 解决问题:使用IOC能够解决的程序耦合性高的问题!! Spring的工厂读取配置文件

image-20200728143515792

IOC程序入门

  1. 建立maven工程,普通Java工程编程

  2. 导入坐标

     
     
     
    x
     
     
     
     
    只须要导入一个Spring Context,经过传递依赖就能够把其余的jar所有导入进来
    <dependencies>
         <!--经过maven窗体依赖,导入依赖的jar包-->
         <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.0.2.RELEASE</version>
         </dependency>
         <!--junit单元测试-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
         <!--日志-->
         <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.12</version>
         </dependency>
         <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
         </dependency>
    </dependencies>
     
  3. 在resources目录下导入log4j.properties

  4. 编写包,编写Service接口和实现类

  5. 在resouces目录下编写配置文件(推荐名为:"applicationContext.xml")

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <?xml version="1.0" encoding="UTF-8" ?><!--文档声明-->
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:tx="http://www.springframework.org/schema/tx"
             xmlns:aop="http://www.springframework.org/schema/aop"
             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/tx
              http://www.springframework.org/schema/tx/spring-tx.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd
              http://www.springframework.org/schema/context
              https://www.springframework.org/schema/context/spring-context.xsd">
       
  6. 编写测试方法,调方法

    小提示:ApplicationContext工厂类 按住快捷键Ctrl+H 能够查看该类的结构

     
     
     
    xxxxxxxxxx
     
     
     
     
    //先建立Spring的IOC的工厂,加载src目录下的配置文件,把配置文件中的类建立成对象,存储到IOC容器中
    ApplicationContext ac = new FileSystemXMlApplicationContext("加载某个磁盘上的文件");
    //ApplicationContext ac = new ClassPathXmlApplicationContext("resources目录下配置文件");
    //从容器中获取对象
    UserService us = (UserService)ac.getBean("配置文件bean标签的id属性获取该对象");//注意:强转,使用接口接收
    //调用对象的方法
    us....
     

 

Spring框架的Bean管理的配置文件方式

  • Bean标签的属性

    • id:--> 对象在IOC容器中惟一的名称,要求编写的时候是惟一的

    • class: --> 管理的类的全路径(包名+类名),经过Java反射技术帮助建立实例对象,建立后存到IOC容器当中,经过id来拿对象

    • scope: --> 建立后对象的生命周期(做用范围)

      • singLeton --> 默认的:单例的,IOC容器中只会存在一个实例的 (通常默认使用)

        • ioc容器中只会存在一个实例的,配置文件一被加载,实例对象就会被建立,生命周期就跟容器是同样的
      • prototype --> 多例的:(每次获取 都会建立新的实例对象)

        • 每从IOC容器中获取对象,才会建立实例对象.销毁工做不禁容器负责
       
       
       
      xxxxxxxxxx
       
       
       
       
      //验证单例和多例的生命周期
      //在service编写构造方法输出内容 配置文件修改单例和多例查询结果 是否先输出构造参数仍是先输出从容器中获取对象以前的内容
       
      • request --> 多列的: request应用在Web项目中,每次HTTP请求都会建立一个新的Bean (基本不用)
      • session --> 多列的: session应用在Web项目中,同一个HTTP Session共享一个Bean (基本不用)
    • init-method ,当bean被载入到容器的时候调用init-method属性指定的方法

      • 通常会用来完成初始化工做: init-method="service实现类方法"
    • destroy-method ,当bean从容器中删除的时候调用destroy-method属性指定的方法

      • 通常会用来完成销毁工做: destroy-method = "service实现类方法"

        • 注意:多例模式看不见销毁的工做,由于多例工厂不负责销毁,多例销毁是由Java虚拟机完成的
 
 
 
xxxxxxxxxx
 
 
 
 
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
 

实例化Bean对象的三种方式(了解)

框架提供建立bean对象的三种方式,基本上都使用默认方式

  • 默认调用无参构造方式
 
 
 
xxxxxxxxxx
 
 
 
 
<bean id="user" class="...."/>
 
  • 静态工厂方式
 
 
 
xxxxxxxxxx
 
 
 
 
//建立StaticFactory实体类
//建立静态create(自定义名User)方法 返回值Service这个类
public class StaticFactory{
     //静态工厂方式
     public static UserService createUser(){
          sout("经过静态工厂的方式建立....")
          return new UserServiceImpl();
     }
}
//配置文件中 "经过StaticFactory类的creatrUser这个静态类获取的对象"  
//优势:编写不少业务逻辑 权限校验...
<bean id="user" class="包名+StaticFactory类" factory-method="createUser" />
//测试类
...
 
  • 实例化工厂的方式
 
 
 
xxxxxxxxxx
 
 
 
 
//建立Dfactory实体类
//动态工厂方式
public class Dfactory{
     //静态工厂方式
     public static UserService createUser(){
          sout("实例化工厂的方式建立....")
          return new UserServiceImpl();
     }
}
<bean id="user" class="包名+Dfactory类" factory-method="createUser" factory-bean="dfactory" />;
//测试类
...
 

多配置文件方式

把全部配置都写在一个配置文件中,太乱,spring支持多配置文件方式

  • 多配置文件方式一:
 
 
 
xxxxxxxxxx
 
 
 
 
//加载多个配置文件
ApplicationContext ac = new ClassPathXmlApplication("applicationContext.xml","application...");//CTRL+P 参数能够有多个 能够加载多个配置文件
 
  • 多配置文件方式二:
 
 
 
xxxxxxxxxx
 
 
 
 
<!-- 引入其余的配置文件 -->
<import resource="applicationContext2.xml"/>
 

IOC技术总结

获取IOC容器对象

ApplicationContext工厂:建立对象都是由工厂来实现的,读取配置文件,底层使用反射机制来建立对象

 

ApplicationContext这个接口底层有2个实现类,Ctrl+H查看

  • FileSystemXmlApplicaitonContext("D:\demo\applicaitonContext.xml") = 加载某个磁盘上的配置文件
  • ClassPathXmlApplicaitonContext=类路径resources目录下 (基本上都用这个)

使用工厂,获取IOC容器中的对象 工厂对象.getBean("bean标签的id别名");

建立Bean对象有三种方式

  1. 默认调用无参构造方式
  2. 静态工厂方式
  3. 实例化工厂的方式

多配置文件方式

加载多个配置文件,获取工厂时,参数能够给多个

或在主配置文件中,增长引入其余的配置文件

DI依赖注入(掌握)

概念

image-20200729075137420

  • IOC和DI的概念

    • IOC : Inverse of Control ,控制反转, 将对象的建立权力反转给Spring !!
    • DI : Dependency Injection ,依赖注入 , 在spring框架负责建立Bean对象时, 动态的将依赖对象注入到Bean组件中

属性的set方法方式注入

引用类型注入:

 
 
 
xxxxxxxxxx
 
 
 
 
//将dao和service都存放到容器中
//在Service里面建立Dao成员属性
//给成员属性提供一个set方法
//最后修改bean标签
<bean id="user" class="...">
<property name="这个类的属性名" ref="引用(bean标签的id属性)"/>
</bean>
 

基本类型注入

 
 
 
xxxxxxxxxx
 
 
 
 
//将dao和service都存放到容器中
//在Service里面建立Dao成员属性
//给成员属性提供一个set方法
//最后修改bean标签
<bean id="user" class="...">
<property name="属性名" value="成员属性基本类型的值"/>
</bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
<!--基本数据类型注入方式-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
     <property name="dao" ref="userDao" />
     <property name="name" value="张三" />
</bean>
 

总结:

  • 只要这个类当中,有其余类的成员属性,并提供set方法,就能够把任何对象注入给这个类

属性构造方法方式注入值

 
 
 
xxxxxxxxxx
 
 
 
 
//写实体类 建立构造方法
//配置文件配置bean
<bean id="惟一的名" class="..">
<constructor-arg name="属性的名称" value="基本类型" ref="引用类型"/>
<constructor-arg name="属性的名称" value="基本类型" ref="引用类型"/>
<constructor-arg name="属性的名称" value="基本类型" ref="引用类型"/>
</>
 
 
 
 
xxxxxxxxxx
 
 
 
 
<!--属性构造器方式注入值-->
<bean id="user" class="cn.dong.domain.User">
     <constructor-arg name="name" value="张三"/>
     <constructor-arg name="age" value="20"/>
</bean>
 

 

数组,集合(List,Set,Map),Properties等的注入

本身通常写程序用的比较少,可是使用多个框架整合的时候,必定得会写

 
 
 
xxxxxxxxxx
 
 
 
 
//写实体类 建立set方法 tostring 数组,集合
//配置文件(给集合属性注入值)
<bean id="" class="">
     //数组
<property name="属性名称">
     <array>//给数组传值
     <value>张三</value>//基本类型的数组
     <value>李四</value>//基本类型的数组
     //<ref></ref>引用类型的数组
     <array/>  
     </property>
     
     //list集合
     <property name="属性名称">
     <list>//给list集合传值
     <value>张三</value>//泛型为基本类型
     <value>李四</value>//泛型为基本类型
     //<ref></ref>泛型为引用类型
     <list/>  
     </property>
     
     //map集合
     <property name="属性名称">
     <map>//给list集合传值
     <entry key-ref="" value/>//泛型为引用类型
     <entry key="" value=""/>//泛型为基本类型
     <entry key-ref="" value=""/>//泛型为基本类型
     <map/>  
     </property>
     
     //属性配置文件 实体类 private Properties properties;
     <property>
     <props>
     <prop key="key..."></prop>
     </props>
     </property>
<bean/>
 

DI依赖注入注解

普通数据类型注解

@Value(value = "字符串或数值") //在属性上增长

 
 
 
xxxxxxxxxx
 
 
 
 
//注意:使用配置文件方式依赖注入,须要提供set方法
//使用注解注入值能够不须要set方法
@Value("张三")
private String name;
@Value(value="29")
private int age;
 

引用类型注解

 
 
 
xxxxxxxxxx
 
 
 
 
//也不用提供set方法 (经常使用)
@Autowired //按类型(和id没有任何关系,容器中有对象就自动装配注入)自动装配的注解
private User user;
//按id名称的方式注入 @Qualifier不能单独使用,须要Autowired一块儿使用
@Autowired
@Qualifier(value="id名称")
//这一个顶第二个两个 (偶尔用)
@Resources(name = "id名称") //Java提供的注解,按名称注入对象,属性名称是name
 

 

Spring框架开发方式

  • 原来编写程序流程

    • 需求:编写service和dao的类, 演示代码 技术选择:持久层使用原始的DBC的程序,链接池选择的是Druid链接池。 建立maven工程,导入开发的jar包
 
 
 
xxxxxxxxxx
 
 
 
 
//建立普通的Java的maven工程
//引入坐标,
<dependencies>
        <!--经过maven窗体依赖,导入依赖的jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--日志实现-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--日志-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!--链接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <!--MySql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
    </dependencies>;
//建立数据库 建立表结构 id主键 用户名 money钱 添加3条数据
...;
//新建包,实体类对应数据库,dao,service
//dao写一个查询全部数据的方法
...
//service...
//测试方法
...
 
  • 第二种写程序的流程IOC开发程序

 
 
 
xxxxxxxxxx
 
 
 
 
//新建编写spring核心配置文件 log4j配置文件
//配置service和dao的bean标签 依赖注入...
//dao 链接池对象注入到spring 配置链接池
<bean id="" class="...">
<property name="driverClassName" value"" />     
<property name="url" value"" />     
<property name="username" value"" />     
<property name="password" value"" />     
</bean>;
//在dao提供DateSource成员属性 建立set方法 privete DataSource dataSource
<bean id="" class="...">
<property name="dataSource" ref="dataSource" />
</bean>
     
 

 

IOC注解方式(掌握)

IOC非纯注解快速入门

IOC注解的方式依赖没有变化

编写接口和实体类

在须要管理的类上增长@Compoent注解

 
 
 
xxxxxxxxxx
 
 
 
 
@Component(value = "user")  //组件,做用:把当前类使用IOC容器进行管理,若是没有指定名称,默认使用类名,首字母是小写,或者本身指定名称
public class UserServiceImpl implents UserService{}
//spring核心配置文件 多配置文件也能够
<!-- 开启注解扫描 -->;
<context:component-scan base-package="cn.dong包名"/>
     
 

以上注解@Component... =

经常使用注解

  1. @Component 普通的类
 
 
 
xxxxxxxxxx
 
 
 
 
@Component(value="annotation")
public class AnnotationServiceImpl implements AnnotationService {
    public void showInfo() {
        System.out.println("显示信息!!");
    }
}
 
  1. @Controller 表现层
  2. @Service 业务层
  3. @Repository 持久层

依赖注入经常使用注解

普通数据类型注解

@Value(value = "字符串或数值") //在属性上增长

 
 
 
xxxxxxxxxx
 
 
 
 
//注意:使用配置文件方式依赖注入,须要提供set方法
//使用注解注入值能够不须要set方法
@Value("张三")
private String name;
@Value(value="29")
private int age;
 

引用类型注解

 
 
 
xxxxxxxxxx
 
 
 
 
//也不用提供set方法 (经常使用)
@Autowired //按类型(和id没有任何关系,容器中有对象就自动装配注入)自动装配的注解
private User user;
//按id名称的方式注入 @Qualifier不能单独使用,须要Autowired一块儿使用
@Autowired
@Qualifier(value="id名称")
//这一个顶第二个两个 (偶尔用)
@Resources(name = "id名称") //Java提供的注解,按名称注入对象,属性名称是name
 

对象生命周期(做用范围)注解

 
 
 
xxxxxxxxxx
 
 
 
 
@Scope(value = "singleton") //默认值,单例的
@Scope(value = "propotype") //多例的
 

初始化方法和销毁方法注解(了解)

 
 
 
xxxxxxxxxx
 
 
 
 
//@PostConstruct 至关于init-method
public void init(){ sout("初始化"); }
//@PreDestroy 至关于destroy-method
public void destroy(){ sout("销毁"); }
 

注解扫描(组件扫描)

使用以上注解须要在Spring的配置文件进行注解扫描,不然无法注入到IOC容器,报错空指针异常

 
 
 
xxxxxxxxxx
 
 
 
 
<!--开启注解扫描(组件扫描)-->
<context:component-scan base-package="cn.dong.service"/>
 

 

IOC纯注解的方式(掌握)

纯注解的方式是微服务架构开发的主要方式,因此也是很是的重要。纯注解的目的是换掉全部的配置文件。可是须要编写配置类。

编写配置类SpringConfig,包SpringConfig,替换掉applicationContext.xml配置文件

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //声明当前类是一个配置类
@ComponentScan(value = {"cn.dong","..."})//配置扫描的包
public class ...{}
编写测试方法
//编写程序,加载配置类
//建立工厂,加载配置类
ApplicaitonCOntext ac = new AnnotationConfigApplicaitonContext(配置类.class);
ac.getBean(....
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
@Service(value="showInfo")//加载类到IOC容器
public class UserServiceImpl implements UserService {//Service业务层
    public void showInfo() {
        System.out.println("业务层显示信息.....");
    }
}
@Configuration //声明当前类是一个配置类
@ComponentScan(value="cn.dong") //配置扫描的包
public class SpringConfig {
}
@org.junit.Test
    public void show(){//测试类
        //建立工厂,加载配置类
        ApplicationContext ac = new AnnotationConfigApplicationContext(UserServiceImpl.class);
        //使用工厂获取对象
        UserServiceImpl service=(UserServiceImpl) ac.getBean("showInfo");
        service.showInfo();
    }
 

引入多个配置类注解

@import注解 String的配置文件能够分红多个配置的,编写多个配置类,用于导入其余配置类

 
 
 
xxxxxxxxxx
 
 
 
 
@Impoer(value={xxx.class,xxx.class})
public class SrpingConfig{}
 

Bean注解(经常使用)

@Bean 只能写在方法上,代表使用此方法建立一个对象,对象建立完成保存到IOC容器中,(用于解决链接池的对象管理等,不少类都不是本身写的,只是拿来用不能随意更改,不能加注解,就得使用bean注解)

 
 
 
xxxxxxxxxx
 
 
 
 
管理IOC,管理链接池对象
/**
* 建立链接池对象,返回对象,把该方法建立后的对象存入到链接池中,使用@Bean注解解决
*/;
@Bean(name="dataSource")//name惟一的
public DataSource source(){
DruidDataSource dataSource = new DruidDataSource();
     dataSource.setUrl("...");
     dataSource.setUsername(".....");
     return dataSource;
}
同等于 Spring配置文件中,配置链接池对象;
<bean id="..." ..>
<property name="" value="..."/>
</bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
持久层;
//Spring模板
@Bean(name="template")
public JdbcTemplate template(){
     //实例化JdbcTemplate对象 Spring模板
     JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
     return template;
}
测试类;
@Test
public void show(){
     //加载配置类,建立工厂
     ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
     //使用工厂对象获取对象
     JdbcTemplate template =(JdbcTemplate) ac.getBean("template");
     //写sql语句
     String sql = "select count(*) from user";
     //数据操做
     Integer i=template.queryForObject(sql, Integer.class);
     System.out.println(i);
}
 

 

总结

经常使用注解(类加载到IOC容器)

  1. @Component(value="id名称") 普通的类
  2. @Controller 表现层
  3. @Service 业务层
  4. @Repository 持久层

这四个注解使用方法,和结果都是同样的,可是仍是推荐哪一个领域写哪一个注解!

 

依赖注入注解

  • 基本类型依赖注入

    • @Value("张三")
  • 引用类型依赖注入

    1. @Autowired 自动装配
    2. @Autowired @Qualifier(value="id名称") 按id名称方式注入
    3. @Resources(name = "id名称") Java提供的注解 也是按id名称注入

 

对象生命周期注解

  • @Scope(value = "singleton") //默认值,单例的
  • @Scope(value = "propotype") //多例的

初始化和销毁注解

  • @PostConstruct 至关于init-method
  • @PreDestroy 至关于destroy-method

IOC纯注解方式

  • @Configuration //声明当前类是一个配置类
  • @ComponentScan(basePackages = {“cn.dong或value")//配置扫描的包

引入多个配置类

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //声明配置类
public class SpringConfig{}
@Configuration //声明配置类
//扫描指定的包结构
@ComponentScan(value="cn.dong")
//引用新的配置类
Import(valueu = {SpringConfig2.class})
public class SpringConfig2{}
 

 

@Bean注解(重要)

只能写在方法上,代表使用此方法建立一个对象,对象建立完成保存到IOC容器中,(用于解决链接池的对象管理等,不少类都不是本身写的,只是拿来用不能随意更改,不能加注解,就得使用bean注解)

Spring整合Junit单元测试(掌握)

  • 每次进行单元测试的时候,都须要编写建立工厂,加载配置文件等代码,比较繁琐。Spring提供了整合Junit单元测试的技术,能够简化测试开发。下面开始学习该技术。
  • 必须先有Junit单元测试的环境,也就是说已经导入Junit单元测试的jar包。我们已经导入过了。使用的是4.12版本再导入spring-test的坐标依赖

快速入门

  1. 检查jar或坐标是否导入,Junit4.12
  2. 导入一个新的坐标依赖 ”spring整合Junit测试jar包“ ,Spring-test5.0.2

配置文件+注解方式

 
 
 
xxxxxxxxxx
 
 
 
 
<!-- 整合单元测试 -->
<bean id="user" class="cn.dong.User"></bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
//运行单元测试
@RunWith(value = SpringJunit4ClassRunner.class) 
//加载类路径下的配置文件
@ConTextConfiguration(value = "classpath:Spring配置文件路径")
public Class Test{
     //测试哪个对象,就把该对象注入进来,在测试环境下,可使用注解方式注入测试的对象
     @Autowired
     private User user;//依赖注入的测试对象
     
     @Test
     public void show(){
          //...
     }
}
 

纯注解方式

 
 
 
xxxxxxxxxx
 
 
 
 
//建立配置类
//声明配置类
@Configuration
//扫描包结构
@CompoentScan(value = "cn.dong要扫描的路径")
public class SpringConfig(){
}
//建立测试类
@RunWith(SpringJunit4ClassRunner.class)//运行单元测试
@ContextConfiguration(classes = SpringConfig.class)//加载配置类
public class Test(){
     //按类型依赖注入
     @Autowired
     private User user;
     @Test
     public void show(){
          user...
     }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
测试类
//运行单元测试
@RunWith(value = SpringJUnit4ClassRunner.class)
//加载路径下的配置文件
@ContextConfiguration(value="classpath:applicationContext.xml")
public class Test3 {
    //依赖注入的测试对象
    @Autowired
    private User user;
    //Junit测试
    @Test
    public void show(){
        user.setName("颤三");
        System.out.println(user);
    }
}
User实体类
@Component
public class User {
 

总结

为何要使用Spring整合的Junit单元测试?

  • 每次进行单元测试的时候,都须要编写建立工厂,加载配置文件等代码,比较繁琐。Spring提供了整合Junit单元测试的技术,能够简化测试开发。下面开始学习该技术。

测试类增长如下注解

  • @RunWith(value = SpringJUnit4ClassRunner.class)//运行单元测试
  • @ContextConfiguration(value="classpath:applicationContext.xml")//加载路径下的配置文件
  • @ContextConfiguration(classes=SpringConfig.class)

在测试类中,增长"依赖注入的测试对象(接口)" 直接使用对象调方法便可 (千万不要忘记: 依赖注入的测试对象 增长@Autowired 自动装配对象到IOC容器管理)

Spring框架AOP技术

AOP概念的引入

建立maven的普通工程,引入开发坐标,跟原来如出一辙

建立包,实体类,业务层,持久层...

导入配置文件

业务层建立2个帐户,持久层建立1个帐户

问题来了:业务层若是有一个帐户建立失败,就不能给数据库添加数据,就应该事务回滚,须要事务管理

  • 开启事务 要用Connection接口,发现dao也须要用到Connection接口,并且还必须用到业务层的Connection接口

    • 第一种方法:方法的参数传递,设计以前参数须要一个Connection接口,谁调用谁传递 (太麻烦)
    • 第二种方法:线程绑定 能够从当前线程中拿到直接绑定的Connection (优先使用)
 
 
 
xxxxxxxxxx
 
 
 
 
//业务层
sout("业务层:保存两个帐号");
//开启事务 要用Connection接口,发现dao也须要用到Connection接口,并且还必须用到业务层的Connection接口
工具类.startTransaction();
//第一种方法:方法的参数传递,设计以前参数须要一个Connection接口,谁调用谁传递   (太麻烦)
//第二种方法:线程绑定 能够从当前线程中拿到直接绑定的Connection (优先使用)
//执行操做
try{
dao.seve(user1);
     //模拟异常
     ...
dao.seve(user2);
//提交事务/回滚事务
工具类.commit();     
} catch(...) {
     //回滚事务打印异常信息
     工具类.rollback();
}finally{
     //关闭资源(归还链接)
     工具类.close();
}
编写持久层dao;
//获取到链接
Connection conn = 工具类.getConnection();
//编写sql
...;
//预编译
PreparedStatement stmt = conn.prepareStatement(sql);
//设置值
stme.setString(1,user.getName());
stmt.setInt(2,user.getMoney());
//执行操做
stmt.executeUpdate();
//关闭资源 conn不能关闭
stmt.close();
 

线程绑定

 
 
 
xxxxxxxxxx
 
 
 
 
业务层
     //DI依赖注入Dao
     UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
     this.dao=dao;
}
/**
     * 保存2个帐户
     * @param user1
     * @param user2
     */
public void save(User user1, User user2) {
     //开启事务:使用第二种方法“线程绑定”
     try {
          AffairUtils.startTransaction();
          //执行操做
          dao.save(user1);
          dao.save(user2);
          //提交事务
          AffairUtils.commit();
     } catch (Exception e) {
          //打印错误信息
          e.printStackTrace();
          //提交回滚
          AffairUtils.rollback();
     } finally {
          //归还链接
          AffairUtils.close();
     }
}
持久层;
public void save(User user) throws SQLException {
     //获取链接
     Connection conn=AffairUtils.getConnection();
     //编写sql
     String sql="insert into `user`.`user` (`name`, `money`) values (?, ?)";
     //预编译
     PreparedStatement stmt=conn.prepareStatement(sql);
     //设置值
     stmt.setString(1, user.getName());
     stmt.setInt(2, user.getMoney());
     //执行操做
     stmt.executeUpdate();
     //关闭资源
     stmt.close();
}
测试类:
@Test
public void show(){
     //加载配置文件,建立工厂
     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
     //使用工厂对象获取对象
     UserService service =(UserService) ac.getBean("userService");
     //建立用户
     User user1 = new User("熊大",1000);
     User user2 = new User("熊二",2000);
     //保存
     service.save(user1,user2);
}
 

使用到的事务工具类: AffairUtils.java

 

业务层开启事务 要用Connection接口,发现持久层也须要用到Connection接口,并且还必须用到业务层的Connection接口

  • 第一种方法:方法的参数传递,设计以前参数须要一个Connection接口,谁调用谁传递 (太麻烦)
  • 第二种方法:线程绑定 能够从当前线程中拿到直接绑定的Connection (优先使用)

加强方法加强(Jdk动态代理设计模式)

以上代码的业务层很是繁琐,在真正开发中,业务层只须要关注业务逻辑,不须要关注其余,因此就须要进行,业务层的方法加强

  • 加强方法的手段

    • 继承(加强方法)
    • 装饰设计模式
    • 动态代理设计模式(推荐使用)
 
 
 
xxxxxxxxxx
 
 
 
 
//建立JdkProxy类
//传入目标对象,生成该对象的代理对象,返回,对目标对象的方法进行加强
//获取代理对象,返回,加强目标对象的方法
public static Object getProxy(UserService userService){
     /**
     * 使用Jdk的动态代理生成代理对象
     */
     Object proxy = Proxy.newProxyInstance(类加载器,传入对象的实现的接口要字节码对象,回调函数匿名内部类);
     //类加载器 JdkProxy.class.getClassLoader()
     //传入对象实现了哪些接口的字节码对象userService.getClass().getInterfaces()
     new InvocationHandler(){//invoke方法参数Object proxy , Method method , Object[] args
          try{
      //开启事务
          //对目标对象的方法进行加强
          Object result = method.invoke(userService,args);
           //提交事务
          }回滚事务...归还链接
          
          return result;
}
     return proxy;
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
测试类:
@Test
public void show(){
     //其余代码省略,请看上方
     //使用工厂对象获取对象
     UserService service =(UserService) ac.getBean("userService");
    
     //生成代理对象
     Object proxyObj= JdkProxy.getProxy(userService);
     //强转
     UserService proxy = (UserService) proxyObj;
     //调用代理对象方法(进行保存到数据库)
     proxy.save(user1,user2);
}
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
业务层;
//DI依赖注入Dao
UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
     this.dao=dao;
}
/**
     * 保存2个帐户
     * @param user1
     * @param user2
     */
public void save(User user1, User user2) throws SQLException {
     //开启事务:使用第二种方法“线程绑定”+Jdk动态代理
     dao.save(user1);
     int i = 100/0;
     dao.save(user2);
}
测试类;
@Test
public void show() throws SQLException {
     //加载配置文件,建立工厂
     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
     //使用工厂对象获取对象
     UserService service =(UserService) ac.getBean("userService");
     //建立用户
     User user1 = new User("熊大",1000);
     User user2 = new User("熊二",2000);
     //生成代理对象
     Object proxyObj=JdkProxy.getProxy(service);
     //强转成Service
     UserService proxy = (UserService)proxyObj;
     //使用代理对象进行保存数据
     proxy.save(user1,user2);
}
 

jdk动态代理类事务管理: JdkProxy.java

AOP的相关概念

写完以上代码,又发现一个问题,使用动态代理模式很是繁琐,若是还要给其余方法加强,好比:事务管理,日志的统计,日志的记录

因此就可使用SpringAOP这个技术,他能干什么: "能够直接对某个方法进行加强,不用你去繁琐的写方法加强"

还有一个问题:动态代理只能加强接口中的方法,没有接口,还不能加强...

AOP的概述

增长方法,就不用本身写代理,能够对某些方法某些个方法进行加强

什么是AOP的技术?

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程

  • AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
  • AOP最先由AOP联盟的组织提出的,制定了-套规范.Spring将AOP思想引入到框架中,必须遵照AOP联盟的规范
  • 经过预编译方式或者运行期动态代理实现程序功能的统一维护的一 -种技术
  • AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的- -种衍 生范型
  • 利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重 用性,同时提升了开发的效率

AOP:面向切面编程.(思想--解决OOP遇到一些问题)

AOP采起横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

为何要学习AOP,能够在不修改源代码的前提下,对程序进行加强! !

 

AOP的优点

总结一句话:AOP能够在不修改源代码的状况下,"对某些方法,某些程序进行加强"

优点:

  1. 减小重复的代码
  2. 提供开发的效率
  3. 维护方便,扩展

AOP底层原理(掌握)

AOP底层实现原理:

  • 底层使用的就是代理技术:

    • JDK的动态代理
    • CGLIB代理技术

为何Spring框架底层会提供多个代理技术呢?

  • 之后写程序不必定都是写接口的,JDK动态代理只能解决接口存在的方法
  • CGLIB代理技术 对类生成代理对象,被代理类是否实现了接口,无所谓 生成class文件,默认继承了被代理对象(子类加强父类的方法是特别容易的)

Spring框架会自动作一个选择,当你的程序有没有接口,默认有:就会用JDK方式加强,若是不是JDK就会使用CGL方式加强

image-20200801141351090

Spring的AOP技术-配置文件

AOP相关的术语(概念)

  1. Joinpoint(链接点)所谓链接点是指那些被拦截到的点。在spring中,这些点指的是方法,由于spring只支持方法类型的链接点

    • Joinpoint"链接点"指的是当前类中的全部的方法(如ServiceImpl全部的方法均可以被称为:"链接点")
  2. Pointcut(切入点) -所谓切入点是指咱们要对哪些oinpoint进行拦截的定义

    • Pointcut "切入点" (编写切入点表达式) ,程序加强的入口(如: 若是你想加强某个方法,就看你的切入点表达式写没写) -->看切入点表达式来决定 此方法增不加强
  3. Advice(通知/加强)--所谓通知是指拦截到Joinpoint以后所要作的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

    • Advice(通知/加强) 指 对save方法要进行加强,编写具体的代码,编写事务管理相关的代码 (要加强的方法,你得写加强的具体代码,就写到通知里面去)
  4. Target(目标对象)--代理的目标对象

    • 目标对象 --> 你想要加强的方法
  5. Weaving(织入)--是指把加强应用到目标对象来建立新的代理对象的过程

    • 把Advice(通知/加强)的方法加强到目标对象过程就是植入,要把代理的东西织入到目标对象的方法当中 (这个技术是Spring作的)
  6. Proxy (代理) - -个类被AOP织入加强后,就产生一个结果代理类

    • 一个类被AOP织入加强后,就残生一个结果代理类 (加强完了,返回给你一个代理类,他是一个字节码文件)
  7. Aspect(切面)--是切入点和通知的结合,之后我们本身来编写和配置的

    • 很抽象的概念, 切面 = 切入点(开启加强切面表达式) + 通知(加强的内容)

作AOP开发,编写的内容

  • 切入点是一个表达式(须要本身编写)
  • 通知/加强(须要本身来编写)

AOP入门程序

需求: 业务层对save方法进行加强(不改变代码对本来打印一条语句改成两条)

步骤:

  1. 导入新的坐标(jar包)

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <!-- AOP联盟 -->
      aopalliance  版本1.0
      <!-- aspectj -->
      aspectjweaver 版本1.8.3
      <!-- spring整合 -->
      spring-aspects 版本5.0.2.ReLEASE
       
  2. 引入AOP的XML的名称空间

     
     
     
    xxxxxxxxxx
     
     
     
     
    xmlns:aop="http://www.springframework.org/schema/aop"
    http://www.springframework.org/schema/aop    https://www.springframework.org/schema/aop/spring-aop.xsd
     
  3. 编写新的类(切面类MyXMLAspect)

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      /**
      * 自定义切面类 = 切入点(表达式) + 通知组成(加强代码)
      */
      public class MyXMlAspect{
           //通知
           public void log(){
                //发送邮件/事务管理/记录日志
                sout("加强方法执行了");
           }
      }
       
  4. 打开Spring核心配置文件applicationContext.xml

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <!--配置切面类,把该类交给IOC容器管理-->
      <bean id="xmlAspect" class="...MyXmlAspect"></bean>
      <!--配置AOP的加强-->
      <aop:config>
           <!--用上面的引用id配置切面 = 切入点 + 通知组成-->
      <aop:aspect ref="xmlAspect">
                <!--前置通知: UserServiceImpl的save方法执行前,会加强-->
           <aop:before method="写切面类通知的方法" pointcut="切入点的表达式execution(public void cn.dong.service.UserServiceImpl.save())"/>
           </aop:aspect>
      </aop:config>
       

切入点的表达式

在配置切入点的时候,须要定义表达式,具体以下:

切入点表达式的格式以下:

  • execution[修饰符] 返回值类型 包名.类名.方法名(参数)

  • 修饰符能够省略不写,不是必需要出现的

  • 返回值类型是不能省略不写的,根据你的方法来编写返回值。可使用 “ * ” 替代。

  • 包名例如:cn.dong.dao.UserDaoImpl

    • 首先cn是不能省略不写的,可是能够*代替
    • 中间的包名可使用*号代替
    • 若是想省略中间的包名可使用..
  • 类名也可使用 * 号代替,也有相似的写法:*UserDaoImpl

  • 方法也可使用 * 号代替

  • 参数若是是一个可使用 * 号代替,若是想表明任意参数使用 ..

 
 
 
xxxxxxxxxx
 
 
 
 
<aop:before method="切面类方法" phintcut="切入点表达式"/>
<!--
切入点的表达式
 execution(描述想对哪一个类的方法进行加强) 固定写法
[public] 修饰符(能够不写)
void返回值 () * (推荐使用* = 支持返回任意值)
包名+类名 * (所有类或包下的类都加强) 或者类名首位* = (*UserDao)以他开头
方法 * 也可使用*开头或者结尾
参数(int,String)或..(推荐使用) 表示任意类型的和个数的参数 = Object..
 
        
通用表达式:execution(public * cn.dong.*.*UserDao.*(..))
注意:加强方法首先找类,找不到不加强方法"并不会报错,包括返回值填错和参数"
-->
 

AOP的通知类型

  1. 前置通知: 目标方法执行前,进行加强
  • <aop:before method="..." pointcut="..." /> (开启事务)
  1. 最终通知: 目标方法执行后成功或者失败,进行加强 (关闭资源)
  • <aop:after method="..." pointcut="..." />
  1. 后置通知: 目标方法执行成功后,进行加强 (提交事务)
  • <aop:after-returning method="..." pointcut="..." />
  1. 异常通知: 目标方法执行失败后,进行加强 (回滚事务)
  • <aop:after-throwing method="..." pointcut="..." />
  1. 环绕通知: 目标方法执行先后,均可以进行加强,目标对象的方法须要手动执行

    • <aop:around method="..." pointcut="..." />

    • 直接使用的问题: 目标对象的方法没有执行,须要手动执行目标对象的方法

      • 在切面类的环绕通知方法增长参数,"ProceedingJoinPoint point"

      • point.procedd(); //让目标对象的方法去执行 (优势:这个方法写在这个位置,以前以后,能够去完成其余操做,这个方法自动会抛出异常,也能够利用异常均可以加强)

      •  
         
         
        xxxxxxxxxx
         
         
         
         
         

总结: 前四个通知能够一块儿使用,环绕通知能够单独使用,就能够完成事务管理

 

Spring的AOP技术-注解

AOP注解方式入门程序

配置文件+注解方式

搭建IOC环境...

搭建AOP环境步骤:

  1. 编写切面类,增长通知方法

  2. @Compoent 把切面类交给IOC容器进行管理

  3. @Aspect //声明切面类 == <aop:aspect ref="myXmlAspect">

  4. 在log通知方法上增长注解:切入点的表达式

    • @Before(value = "切入点的表达式") //前置通知
    • @After //最终通知
    • @AfterReturning //后置通知
    • @AfterThrowing //异常通知
    • @Around //环绕通知 ,目标对象方法须要手动执行
  5. 开启AOP自动代理(在Spring核心配置文件配置)

    • <aop:aspectj-autoproxy />

AOP纯注解方式

开启AOP的自动代理 换成 配置类

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //配置类
@ComponentScan(value = "扫描下包名") // 扫描包
@EnableAspectJAutoFroxy //开启自动代理 == (aop:aspectj-autoproxy) />
public class SpringConfig(){}
 

 

总结:

切入点表达式

execution(public * cn.dong..UserDao.*(..))

通知类型注解

  • @Before(value = "切入点的表达式") //前置通知
  • @After //最终通知
  • @AfterReturning //后置通知
  • @AfterThrowing //异常通知
  • @Around //环绕通知 ,目标对象方法须要手动执行

AOP纯注解步骤

建立一个配置类,增长如下注解

  • @Configuration //配置类
  • @ComponentScan(value = "扫描下包名") // 扫描包
  • @EnableAspectJAutoFroxy //开启自动代理

建立切面类增长如下注解:

  • @Compoent //将切面类交给IOC容器管理
  • @Aspect //声明切面类
  • 在切面类的通知方法上增长通知类型注解...

 

若是不玩纯注解配置文件增长如下代码:

  • <aop:aspectj-autoproxy />

 

总结一句话:AOP能够在不修改源代码的状况下,"对某些方法,某些程序进行加强"

案例

需求:查询数据库的所有用户信息,使用纯注解方式

 
 
 
xxxxxxxxxx
 
 
 
 
测试类;
@RunWith(value=SpringJUnit4ClassRunner.class)//运行单元测试
@ContextConfiguration(classes=SpringConfig.class)//扫描配置类
public class Test {
    @Autowired //自动装配到IOC容器管理
    private UserService service;
    @org.junit.Test
    public void show(){
        service.findAll();
    }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
userServiceImpl实现类;
@Service
public class UserServiceImpl implements UserService {
    /**
     * 获取Dao持久层
     */
    @Autowired
    UserDaoImpl dao;
    /**
     * 查询所有用户信息
     * @return
     */
    public List<User> findAll() {
        System.out.println(dao.findAll());
        return dao.findAll();
    }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
spring配置类;
@Configuration //声明当前是一个配置类
@ComponentScan(value="cn.dong") //配置扫描的包
@EnableAspectJAutoProxy //开启自动代理
/**
 * Spring配置类
 */
public class SpringConfig {
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
Dao实现类;
/**
 * 持久层
 */
@Repository
public class UserDaoImpl implements UserDao {
     /**
     * 获取JdbcTemplate对象
     */
     public JdbcTemplate template() {
          //获取JdbcTemplate对象
          JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
          return template;
     }
     /**
     * 查询全部用户
     * @return
     */
     public List<User> findAll() {
          //写sql语句
          String sql="select * from user ";
          return template().query(sql, new BeanPropertyRowMapper<User>(User.class));
     }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
切面类(加强方法);
/**
 * 自定义切面类 并声明切面类将切面类交给IOC容器管理
 */
@Aspect
@Component
public class MyXmlAspect {
    /**
     *后置通知
     */
    @After("execution(public * cn.dong.service.UserService.findAll(..))")
    public void log(){
        System.out.println("查询了用户,关闭了程序");
    }
}
 

Spring框架的JDBC模板技术(掌握)

JDBC模板技术概述

什么模板技术: Spring框架中提供了不少持久层的模板类来简化编程,使用模板类写程序会变的简单

  • template "模板" 发音:谭普累特
  • 都是Spring框架提供XxxTemplate

提供了Jdbc模板,Spring框架提供的

  • JdbcTemplate类,Connection 表示链接,事务管理 Statement ResultSet

JDBC的模板类使用

导入坐标

 
 
 
xxxxxxxxxx
 
 
 
 
<dependencies>
        <!--经过maven窗体依赖,导入依赖的jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--日志实现-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--日志接口-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!--链接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <!--MySql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <!--spring整合Junit测试jar包-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--AOP联盟-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!--aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!--spring整合-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
      <!--JDBC-->
        <dependency>
            <groupId>maven_repository.org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--事务-->
        <dependency>
            <groupId>maven_repository.org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
 

编写开发方式

 
 
 
xxxxxxxxxx
 
 
 
 
使用new对象方式完成;
//建立链接池对象 Spring框架内置链接池对象
DriverManagerDataSource dataSource = new ...();
//设置四大参数 数据库 帐号 密码 包+类
...
//建立对象,提供模板
JdbcTempate template = new JdbcTemplate(链接池对象);
 
  • 建立对象,提供模板

    • JdbcTempate template = new JdbcTemplate(链接池对象);
  • 方法

    • setDataSource(链接池对象) 获取链接池
    • Update 增删改操做 参数("sql语句",Object可变参数)
 
 
 
xxxxxxxxxx
 
 
 
 
SpringIOC方式编写程序;
Spring配置文件配置链接池和模板;
<!--配置链接池-->
     <bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
     <property name="driverClassName" value= "..." />
     <property name= "url" value= "..." />
     <property name= "username" value="..." />
     <property name=" password" value="..." />
</bean>
<!--配置jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
测试方法;
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfigurgation(value = "classpath:applicationContext.xml")
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void run1(){
....
}
 

Spring框架管理开源的链接池

配置开源的链接池,使用Druid开源的链接池,引入坐标 druid (德洛依)

druid属性配置文件: druid.properties

 
 
 
xxxxxxxxxx
 
 
 
 
第一种方式;
<!--引入外部属性文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfiggurer">
<property name="location" value="classpath:druid.properties"/>
</bean>
第二种方式;
<context:property-placeholder location="classpath:druid.properties"/>
     <bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
     <property name="driverClassName" value= "${配置文件的key}" />
     <property name= "url" value= "${...}" />
     <property name= "username" value="${...}" />
     <property name=" password" value="${...}" />
</bean>
 

 

增删改查范例:

修改

 
 
 
xxxxxxxxxx
 
 
 
 
@Test
    public void show2(){
        int i=template.update("update user set name = ?,money = ? where id = ?", "光头强", 10, 16);
        System.out.println(i);
    }
 

删除

 
 
 
xxxxxxxxxx
 
 
 
 
@Test
    public void show3(){
        template.update("delete from user where id = ?",16);
    }
 

查询: 根据主键查询数据

 
 
 
xxxxxxxxxx
 
 
 
 
//queryForObject("sql语句",RowMapper<T>实体类封装查询数据 , Obect..数据)
User user = jdbcTemplate.queryForObject("select * from user where id=?",new BeanMapper());
//新建实体类,用来进行数据封装的 实现RowMapper<T要封装的类型>{
class BeanMapper implements RowMapper<Account>{
//建立user对象
          User user = new User();
          //封装数据
          account.setId(resultSer.getInt("数据库对应的值id"));
          account.setName(resultSer.getInt("数据库对应的值name"));
          account.setMoney(resultSer.getInt("数据库对应的值money"));
          reretn user;
}
}
查询:查询所有()
//queryForObject("sql语句",RowMapper<T>实体类封装查询数据 , Obect..数据)
User user = jdbcTemplate.queryForObject("select * from user",new BeanMapper());
 

 

 
 
 
xxxxxxxxxx
 
 
 
 
/**
     * 根据主键查询用户信息
     */
@Test
public void show3(){
     User user=template.queryForObject("select * from user where id = ?", new BeanPropertyRowMapper<User>(User.class),1);
     System.out.println(user);
}
/**
     * 查询所有用户信息
     */
@Test
public void show4(){
     List<User> list=template.query("select * from user", new BeanPropertyRowMapper<User>(User.class));
     System.out.println(list);
}
 

转帐案例

业务层: 转帐方法,三个参数: ont付款人 in收款人 money金额

持久层: 付款 收款 2个方法 各为2个参数

 
 
 
xxxxxxxxxx
 
 
 
 
测试类;
@Autowired
private UserService service;
@Test
public void show(){
     service.pay(2,1,500);
}
业务层;
public class UserServiceImpl implements UserService {
    //获取dao
    private UserDao dao;
    public void setDao(UserDao dao) {
        this.dao=dao;
    }
    public void pay(int out, int in, int money) {
        //收钱
        dao.inMoney(in,money);
        //给钱
        dao.outMoney(out,money);
    }
}
持久层;
/**
     * 获取IOC容器中的JdbcTemplate对象
     */
private JdbcTemplate template;
public void setTemplate(JdbcTemplate template) {
     this.template=template;
}
/**
     * 发款
     * @param out
     * @param money
     */
public void outMoney(int out, int money) {
     template.update("update user set money = money - ? where id = ?",money,out);
}
/**
     * 收款
     * @param in
     * @param money
     */
public void inMoney(int in, int money) {
     template.update("update user set money = money + ? where id = ?",money,in);
}
 

注意事项:

发现了一个问题 , 持久层的JdbcTemplate的模板 成员属性还有set方法,

每一次有个新的dao类,就得写一次jdbc模板和set方法,太繁琐,太麻烦 ,

这时候能够定义一个父类,把模板写到父类当中 ,

可是我们不用管,Spring框架已经帮忙写好了直接继承就好

  • extends JbdcDaoSupport "这个模板类里面有JdbcTemplate ,也有set方法find修饰的因此你不能写直接用父类的便可 " 使用方法以下:
 
 
 
xxxxxxxxxx
 
 
 
 
public void outMoney(int out, int money) {
     this.getJdbcTemplate().update("update user set money = money - ? where id = ?",money,out);
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
配置文件;
模板类能够不用配置
在配置dao时,直接依赖注入链接池
<bean id="userDao" class="cn.dong.dao.UserDaoImpl">
<property name="别名" ref="链接池引入id(别名)"/>
</bean>
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
/**
     * 收款
     * @param in
     * @param money
     */
    public void inMoney(int in, int money) {
        this.getJdbcTemplate().update("update user set money = money + ? where id = ?",money,in);
    }
<!--引入外部属性文件-->
    <context:property-placeholder location="classpath:druid.properties"/>
    <!--配置Druid链接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driverClassName}" />
        <property name="url" value="${url}" />
        <property name="username" value="root" />
        <property name="password" value="${password}" />
    </bean>
    <!--配置实体类加载到IOC容器-->
    <bean id="service" class="cn.dong.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>
    <bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
        <!--依赖注入链接池-->
        <property name="dataSource" ref="dataSource" />
    </bean>;
 

 

Spring的事务管理(掌握)

Spring框架的事务管理相关的类和API

 
 
 
xxxxxxxxxx
 
 
 
 
1. PlatformTransactionManager接口     -- 平台事务管理器.(真正管理事务的类)。该接口有具体的实现类,根据不一样的持久层框架,须要选择不一样的实现类!
2. TransactionDefinition接口          -- 事务定义信息.(事务的隔离级别,传播行为,超时,只读)
3. TransactionStatus接口              -- 事务的状态
4. 总结:上述对象之间的关系:平台事务管理器真正管理事务对象.根据事务定义的信息TransactionDefinition 进行事务管理,在管理事务中产生一些状态.将状态记录到TransactionStatus中
5. PlatformTransactionManager接口中实现类和经常使用的方法
    1. 接口的实现类
        * 若是使用的Spring的JDBC模板或者MyBatis框架,须要选择DataSourceTransactionManager实现类
        * 若是使用的是Hibernate的框架,须要选择HibernateTransactionManager实现类
    2. 该接口的经常使用方法
        * void commit(TransactionStatus status) 
        * TransactionStatus getTransaction(TransactionDefinition definition) 
        * void rollback(TransactionStatus status) 
6. TransactionDefinition
    1. 事务隔离级别的常量
        * static int ISOLATION_DEFAULT                  -- 采用数据库的默认隔离级别
        * static int ISOLATION_READ_UNCOMMITTED 
        * static int ISOLATION_READ_COMMITTED 
        * static int ISOLATION_REPEATABLE_READ 
        * static int ISOLATION_SERIALIZABLE 
    2. 事务的传播行为常量(不用设置,使用默认值)
        * 先解释什么是事务的传播行为:解决的是业务层之间的方法调用!!
        * PROPAGATION_REQUIRED(默认值) -- A中有事务,使用A中的事务.若是没有,B就会开启一个新的事务,将A包含进来.(保证A,B在同一个事务中),默认值!!
        * PROPAGATION_SUPPORTS          -- A中有事务,使用A中的事务.若是A中没有事务.那么B也不使用事务.
        * PROPAGATION_MANDATORY         -- A中有事务,使用A中的事务.若是A没有事务.抛出异常.
        * PROPAGATION_REQUIRES_NEW(记)-- A中有事务,将A中的事务挂起.B建立一个新的事务.(保证A,B没有在一个事务中)
        * PROPAGATION_NOT_SUPPORTED     -- A中有事务,将A中的事务挂起.
        * PROPAGATION_NEVER             -- A中有事务,抛出异常.
        * PROPAGATION_NESTED(记)     -- 嵌套事务.当A执行以后,就会在这个位置设置一个保存点.若是B没有问题.执行经过.若是B出现异常,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)
 

TransactionDefinition接口事务的传播行为: 解决业务层方法相互调用,事务传播问题 (使用默认值)

image-20200802152751941

声明式事务管理代码编写:

步骤一: 配置平台事务管理器

 
 
 
xxxxxxxxxx
 
 
 
 
<!--配置平台事务管理器-->
<bean id="transactionMavager" class="DataSourceTransactionMavager">
<!--依赖注入链接池-->
     ...
</bean>
 

步骤二: 配置平台事务通知

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入tx名称空间-->
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
<!--配置平台事务通知(没有本身编写切面类,通知方法也是很多本身编写的,Spring框架提供的)-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
     <!--对方法进行加强,设置隔离级别,传播行为,超时的时间-->
<tx:mehod name="方法名" isolation="DEFAULT默认" propagation="REQUIRED默认" read-only="是不是只读的事务(查询的时候能够设置为只读) timeout="事务超时时间(-1永久)"/><tx:mehod name="方法名"/><!--能够配置多个--?
</tx:advice>
 

步骤三: 配置AOP的加强 (Spring框架提供的系统通知)

 
 
 
xxxxxxxxxx
 
 
 
 
<!--配置AOP的加强-->
<aop:config>
     <!--Spring框架提供的系统通知,使用advisor标签-->
<aop:advisor advice-ref="txAdvice事务通知id" pointcut="execution(public * 包名+类名+方法名(..))" />
</aop:config>
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置Druid链接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="${driverClassName}" />
     <property name="url" value="${url}" />
     <property name="username" value="root" />
     <property name="password" value="${password}" />
</bean>
<!--配置实体类加载到IOC容器-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
     <property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
     <!--依赖注入链接池-->
     <property name="dataSource" ref="dataSource" />
</bean>
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <!--依赖注入链接池-->
     <property name="dataSource" ref="dataSource" />
</bean>
<!--配置平台事务通知-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
     <!--对方法进行加强,设置隔离级别,传播行为,超时时间...-->
     <tx:attributes>
          <tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
     </tx:attributes>
</tx:advice>
<!--配置AOP的加强-->
<aop:config>
     <!--Spring框架提供的系统通知,使用advisor标签-->
     <aop:advisor advice-ref="txAdvisor" pointcut="execution(public * cn.dong.service.impl.UserServiceImpl.pay(..))" />
</aop:config>
 

配置文件+注解,声明式事务管理

配置文件能够更改的地方有: 配置事务的通知 , 和配置AOP的加强(这些均可以省略不写使用注解代替)

步骤一: 开启注解的扫描

 
 
 
xxxxxxxxxx
 
 
 
 
在Spring配置开启注解的扫描
<context:component-scan base-package="xn.dong"/>
给持久层和业务层增长注解,把类交给IOC容器进行管理
在业务层 依赖注入dao 使用@Autowired注解
持久层依赖注入 jdbcTemplate (但在以前先在配置文件中将jdbcTemplate放到IOC容器管理)
开启事务对注解的支持
<tx:annotation-driven transaction-mavager="transactionManager" />
在Service增长注解@Transactional = 对Service的全部方法进行事务管理 也能够增长到方法中 对当前方法进行事务管理
@Transactional(isolation = Isolation.DEFAULT) //设置隔离级别 (能够点进注解查看属性)
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入外部属性文件-->
    <context:property-placeholder location="classpath:druid.properties"/>
    <!--配置Druid链接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driverClassName}" />
        <property name="url" value="${url}" />
        <property name="username" value="root" />
        <property name="password" value="${password}" />
    </bean>
    <!--注解扫描-->
    <context:component-scan base-package="cn.dong" />
    <!--加载到IOC容器管理-->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate" >
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--开启事务对注解的支持-->
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!--配置平台事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--依赖注入链接池-->
        <property name="dataSource" ref="dataSource" />
    </bean>
dao;@Repository("dao")
@Autowired
private JdbcTemplate template;
service;@Service("service")
@Autowired
private UserDao dao;
 

 

纯注解,声明式事务管理

 
 
 
xxxxxxxxxx
 
 
 
 
建立配置类,
扫描包
链接池
使用@Bean 注解 //把链接池保存到IOC容器中
模板对象
使用@Bean   //把JdbcTemplate保存到IOC容器中
@Resource  //不只能够做用在属性上,也能够做用在方法上
平台事务管理器
使用@Bean   //把JdbcTemplate保存到IOC容器中
@Resource  //不只能够做用在属性上,也能够做用在方法上
开启事务注解
@EnableTransactionManagement //开启事务注解
 

范例:

 
 
 
xxxxxxxxxx
 
 
 
 
配置类;
/**
 * Spring配置类
 */
@Configuration //声明配置类
@ComponentScan(value="cn.dong") //扫描包
@EnableTransactionManagement
public class SpringConfig {
    /**
     *   建立链接池对象
     */
    @Bean("dataSource")
    public DataSource dataSource(){
        //建立链接池对象,Spring框架内置了链接池
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        //设置四个参数
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai");
        dataSource.setUsername("root");
        dataSource.setPassword("accp");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }
    /**
     * 建立Spring模板的JdbcTemplate对象
     * @return
     */
    @Bean
    @Resource(name="dataSource")
    public JdbcTemplate jdbcTemplate(){
        //建立JdbcTemplate对象
        JdbcTemplate template=new JdbcTemplate();
        //存放链接到JdbcTemplate
        template.setDataSource(dataSource());
        return template;
    }
    /**
     * 建立平台事务管理对象
     * @return
     */
    @Bean
    @Resource(name="dataSource")
    public PlatformTransactionManager createTransactionManager(){
        DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource());
        return manager;
    }
}
@Service("service")
@Transactional(isolation=Isolation.DEFAULT) //对此类中全部方法都增长事务管理
public class UserServiceImpl implements UserService {
    //获取dao
    @Autowired
    private UserDao dao;
    public void pay(int out, int in, int money) {
        //收钱
        dao.inMoney(in,money);
       int i = 100/0;
        //给钱
        dao.outMoney(out,money);
    }
}
测试类;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfig.class)
public class Demo {
    @Autowired
    private UserService service;
    @Test
    public void show(){
        service.pay(2,1,100);
    }
}
 

 

总结:

相关文章
相关标签/搜索