Spring核心相关知识

第一章spring框架

spring框架就是把我们项目中的成千上万个管理起来,使得他们之间的关系变得松散,这样使得模块中一个类的变化对其他类的影响小,这样对项目的改动和变化就相对容易一些。也就是解耦合,让我们的程序升级容易,改变容易,增加功能容易。帮助我们创建对象,并且管理对象。

spring功能:

spring第一个功能:ioc 控制反转
IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。
描述的:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。

控制: 创建对象,对象的属性赋值,对象之间的关系管理。
反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,
给属性赋值。

正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
public static void main(String args[]){
Student student = new Student(); // 在代码中, 创建对象。–正转。

容器:是一个服务器软件, 一个框架(spring)

使用ioc的目的:

为什么要使用 ioc : 目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。

spring配置文件的标志

在这里插入图片描述

从类路径加载文件 需要将resources里面的配置文件 复制到classes类加载文件中 具体看我的Mybatis

在这里插入图片描述

spring初始的创建

在这里插入图片描述

依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>


在这里插入图片描述
实现类
在这里插入图片描述
beans.xml配置文件
在这里插入图片描述
测试

/**
     * spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中的所有的对象。
     * spring创建对象:默认调用的是无参数构造方法
     */
   @Test
    public void test02(){
        //使用spring容器创建的对象
       //1.指定spring配置文件的名称
       String config="beans.xml";
       //2.创建表示spring容器的对象, ApplicationContext
       // ApplicationContext就是表示Spring容器,通过容器获取对象了
       // ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
       ApplicationContext ac = new ClassPathXmlApplicationContext(config);

       //从容器中获取某个对象, 你要调用对象的方法
       //getBean("配置文件中的bean的id值")
       SomeService service = (SomeService) ac.getBean("someService");

       //使用spring创建好的对象
       service.doSome();

   }

执行结果:
在这里插入图片描述

获取容器对象的数量和名称

在这里插入图片描述

第二章利用di对java对象的2种赋值方法

在这里插入图片描述
set注入只是调用了student的set方法 所以有set方法就可以执行,没有就不能执行bean里面的propery

基于xml的di 配置文件中

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

赋值成功。
在这里插入图片描述

引用类型的xml的set注入

在这里插入图片描述
在这里插入图片描述
applicationContext配置文件
在这里插入图片描述
输出
在这里插入图片描述
构造注入(理解就好)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

@Mapper注解的原因

@Mapper 是 Mybatis 的注解,和 Spring 没有关系,@Repository 是 Spring 的注解,用于声明一个 Bean。
使用 Mybatis 有 XML 文件或者注解的两种使用方式,如果是使用 XML 文件的方式,我们需要在配置文件中指定 XML 的位置,这里只研究注解开发的方式。

在这里插入图片描述
在 Spring 程序中,Mybatis 需要找到对应的 mapper,在编译的时候动态生成代理类,实现数据库查询功能,所以我们需要在接口上添加 @Mapper 注解。

@Reposity注解的原因

首先是使用配置文件 有一个dao类 dao类中有userdao和它的实现类userdaoimpl类和service类 service类中有service接口类和它的实现类serviceimpl类;
在serviceimpl类中会出现下图:
在这里插入图片描述

private UserDao dao = new UserDaoImpl();
这是以往的做法,这样会把程序的值写死,不好添加或者更改程序代码,
所以我们会在applicationContext配置文件中注入Userdaoimpl的对象
也就是
<bean id="userdao" class="com.bjpowernode.dao.impl.UserDaoimpl/>
上面的这一行代替我们上面的那一行代码。此时我们就可以把上面的代码写成
private UserDao dao;
在我们学习了注解之后,我们会用@Reposity代替我们的配置文件的哪一行代码

@Autowired和@Service的来由

在这里插入图片描述

上图的声明service对象的配置方法 就相当于是在serviceimpl类
里面写上@Service创建serviceimpl对象,
下面的<property name ="dao" ref="mysqlDao"/>就相当于在
private UserDao dao;代码上添加@Autowired注解实现自动注入

在这里插入图片描述
上面的图确确实实实现了自动注入byName的方式,其中下面的与属性名一致的意思是 在student实体类中存在school属性 所以我们在实现自动注入的同时,需要把配置文件中bean的school类对象的id与student类的school类型保持一致。

多配置文件

在这里插入图片描述
在school里面就是声明school对象 代码如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
	   http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--School模块所有bean的声明, School模块的配置文件-->
    <!--声明School对象-->
    <bean id="mySchool" class="com.bjpowernode.ba06.School">
        <property name="name" value="航空大学"/>
        <property name="address" value="北京的海淀区" />
    </bean>
</beans>

在student里面就是声明student对象 代码如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
	   http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
      student模块所有bean的声明
    -->
    <!--byType-->
    <bean id="myStudent" class="com.bjpowernode.ba06.Student"  autowire="byType">
        <property name="name" value="张飒" />
        <property name="age" value="30" />
        <!--引用类型-->
        注释:<!--<property name="school" ref="mySchool" />-->
    </bean>
</beans>

基于注解的di

使用注解不仅要加入刚开始的spring-context依赖 还需要添加spring-aop依赖,当然随着spring-context依赖的加入,我们需要的spring-aop依赖也被间接的自动加入了进来。

注解的使用步骤

1.添加依赖 也就是上面的spring-context依赖

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
</dependency>

2.创建类,在指定的类中添加我们所需要的注解
3.在spring的配置文件中加入一个组件扫描器的标签,说明注解在你项目之中的位置。
4.使用注解创建对象,创建容器applicationContext
在这里插入图片描述
三种包的指定方式:

在这里插入图片描述

@Component是在实体类中的注解 目的是在容器中创建实体类的对象
@value是与其对应的注解方式
@Autowired是在用引用类型的时候添加的注解,同时被引用的实体类也需要添加@Component注解。

几个注解

mapper是mybatis的注解 repository是spring的注解
在这里插入图片描述
在这里插入图片描述
一般这样直接在项目中引用@Resource注解是报错的
解决办法:Spring项目中缺少javax.annotation包的依赖。在maven配置文件pom.xml中加入依赖。

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

加入依赖后 运行成功。和@Autowired一样的功能 只不过@Autowired默认是byType注入 而@Resource默认是byName注入

总结

在这里插入图片描述

第三章AOP

动态代理是什么?

1.动态代理
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口

cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。
子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

动态代理的作用

1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离。

动态代理的理解

1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)就是5个注解
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能 -就是execution

AOP面向切面编程

3.Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,
让开发人员用一种统一的方式,使用动态代理。

  1. AOP(Aspect Orient Programming)面向切面编程
    Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
    切面的特点: 一般都是非业务方法,独立使用的。
    Orient:面向, 对着。
    Programming:编程

oop: 面向对象编程

术语:

1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。
非业务功能, 常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。
2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
5)Advice:通知,通知表示切面功能执行的时间。

***说一个切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。***

aop的实现

aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。
spring主要在事务处理时使用aop。
我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。

2.aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使用xml的配置文件 : 配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

aspectj框架的使用

1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After

2)表示切面执行的位置,使用的是切入点表达式。
在这里插入图片描述

	com.service.impl
	com.bjpowrnode.service.impl
	cn.crm.bjpowernode.service


  execution(* *..service.*.*(..))

表示任意返回类型 包或者子包下的service包下的任意包下的任意方法(任意方法参数)

在这里插入图片描述

使用aspectj框架实现aop

使用aop:目的是给已经存在的一些类和方法,增加额外的功能。 前提是不改变原来的类的代码。
使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
1)spring依赖
2)aspectj依赖
3)junit单元测试
3.创建目标类:接口和他的实现类。
要做的是给类中的方法增加功能
在这里插入图片描述

4.创建切面类:普通类
1)在类的上面加入 @Aspect
2)在类中定义方法, 方法就是切面要执行的功能代码
在方法的上面加入aspectj中的通知注解,例如@Before
有需要指定切入点表达式execution()
在这里插入图片描述

@Before注解

在这里插入图片描述

5.创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件
1)声明目标对象
2)声明切面类对象
3)声明aspectj框架中的自动代理生成器标签。
自动代理生成器:用来完成代理对象的自动创建功能的。

//@service将目标类放入容器中
在这里插入图片描述

//① 在类上使用 @Component 注解 把切面类加入到IOC容器中
//② 在类上使用 @Aspect 注解 使之成为切面类
execution
上图中execution是可以给单个类中的方法增加功能的 而且还可以对多个类增加相同的功能(只通过改变execution里面的参数范围就行)
在这里插入图片描述

6.创建测试类,从spring容器中获取目标对象(实际就是代理对象)。
通过代理执行方法,实现aop的功能增强。
在这里插入图片描述

注意

当读取配置文件到这个代码的时候
aop:aspectj-autoproxy/
此时就会一个一个找对应可用的切面类的注解,先找@service,哦这个注解不是,继续找,到@Aspect 哎呀找到了就是你,然后就会生成代理对象,执行@Before注解下的方法 @Before注解后面的execution里面是原有的功能方法,所以此时 @Before注解下的方法就会在原有的功能方法之前执行。

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

JoinPoint

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

@Afterunning注解

在这里插入图片描述
在这里插入图片描述
returning 自定义的变量,表示目标方法的返回值的。
自定义的变量名必须和通知方法的形参名一样。也就是下图的样子:
在这里插入图片描述

目标类添加doOther方法
在这里插入图片描述
在这里插入图片描述
上图的return返回值,可以被后面的切面类中的AfterRunning注解下的方法获取 并且改变它的返回值:也即是下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图是执行的结果。

@Around

设置前置和后置通知

在这里插入图片描述
执行结果:
在这里插入图片描述

控制目标方法是否执行(故而经常做事务)

在这里插入图片描述
在这里插入图片描述
@around的ProceedingJoinPoint 的作用就是用来执行目标方法的,可以通过
ProceedingJoinPoint 调用目标方法的参数 通过获取的参数和自己在around设置的条件信息进行比较 如果相等就执行目标方法,如果不相等就不执行目标方法,从而达到控制目标方法执行的目的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
显然这里是自己设定的zy 肯定等于获取的地有个参数值zy 所以会执行目标方法。
执行结果:
在这里插入图片描述

修改目标方法的返回值

原有的返回值
在这里插入图片描述
修改
在这里插入图片描述
执行
在这里插入图片描述

在这里插入图片描述
实际上,环绕通知 就是使得接口实现类对象直接调用了around注解下的方法。如下图所示:
在这里插入图片描述
1是等于2的 这就是环绕通知的特殊之处。

所以目标方法经常做事务,在目标方法之前开启事务,执行目标方法,然后关闭事务。(用到控制目标方法执行的作用)

@Pointcut辅助execution复用功能

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只是一个辅助功能 没有其他重要的作用了。

第四章spring集成Mybatis

:把mybatis框架和spring集成在一起,向一个框架一样使用。也就是说,以后就不用单独的使用mybatis框架了,而是spring集成mybatis,当然通过spring的ioc容器,mybatis就不用自己创建对象了。

回顾mybatis

mybatis使用步骤,对象
1.定义dao接口 ,StudentDao
2.定义mapper文件 StudentDao.xml
3.定义mybatis的主配置文件 mybatis.xml
4.创建dao的代理对象, StudentDao dao = SqlSession.getMapper(StudentDao.class);
List students = dao.selectStudents();

要使用dao对象,需要使用getMapper()方法,
怎么能使用getMapper()方法,需要哪些条件
1.获取SqlSession对象, 需要使用SqlSessionFactory的openSession()方法。
2.创建SqlSessionFactory对象。 通过读取mybatis的主配置文件,能创建SqlSessionFactory对象

需要SqlSessionFactory对象, 使用Factory能获取SqlSession ,有了SqlSession就能有dao , 目的就是获取dao对象
Factory创建需要读取主配置文件

mybatis自己带的连接池比较弱,我们用功能强大的阿里连接池来代替,我们会使用独立的连接池类替换mybatis默认自己带的, 把连接池类也交给spring创建。所以在spring整合mybatis中,下面的environment就会被pass掉!!!!!!

主配置文件:
1.数据库信息

 <environment id="mydev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/数据库名"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
            
  1. mapper文件的位置
<mappers>
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
    </mappers>

spring和mybatis的集成步骤:

1.新建maven项目
2.加入maven的依赖
1)spring依赖
2)mybatis依赖
3)mysql驱动
4)spring的事务的依赖
5)mybatis和spring集成的依赖: mybatis官方体用的,用来在spring项目中创建mybatis
的SqlSesissonFactory,dao对象的

 <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--spring核心ioc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--做spring事务用到的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <!--阿里公司的数据库连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
  </dependencies>

  <build>

    <!--目的是把src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    </bulid>

3.创建实体类(这里我直接把注解spring注解写上了)
在这里插入图片描述

4.创建dao接口和mapper文件(4-5部一样 添加了@Mapper)
在这里插入图片描述

5.(添加@Mapper注解)创建mybatis主配置文件
6.创建Service接口和实现类,属性是dao。(这里我还添加了student属性 让student注入进来 这也是为什么 在student加注解 就不用在spring配置文件中写了 只用在配置文件中添加组件扫描器就行)
在这里插入图片描述

7.创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源DataSource
2)SqlSessionFactory
3) Dao对象
4)声明自定义的service

8.创建测试类,获取Service对象,通过service调用dao完成数据库的访问

(1) 数据源的配置(掌握)

使用 JDBC 模板,首先需要配置好数据源,数据源直接以 Bean 的形式配置在 Spring 配
置文件中。根据数据源的不同,其配置方式不同:

Druid 数据源 DruidDataSource

Druid 是阿里的开源数据库连接池。是 Java 语言中最好的数据库连接池。Druid 能够提供强大的监控和扩展功能。

官网:https://github.com/alibaba/druid
使用地址:https://github.com/alibaba/druid/wiki/常见问题

数据源:数据的源头,需要设置数据库url,用户名和密码,此时就相当于一个代理数据库;它包含连接池和连接池管理两个部分;

Java中的数据源就是javax.sql.DataSource。DataSource是Java定义的接口,可以有不同的实现。

连接池:一个连接相当于数据源和dao层的管道,那连接池就相当于存放了很多管道的池子;我们获取连接不从数据源取而是从连接池取。

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

上面(3)的指定文件mybatis已经由@Mapper所代替,写的时候可以在StudentDao接口类上加上注解即可 就不用在配置文件中写了

在这里插入图片描述

Spring 全部配置文件版本(没有写mapper注解的spring整合mybatis配置文件):

在这里插入图片描述
最后一行的@Service已经代替 而且studentDao值也通过@Autowired所注入,所以在配置文件中不写。

spring配置文件@Mapper版本

<?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: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 https://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--下面就是spring配置mybatis的配置文件了  数据源  sqlsessionFactory-->
    <!--    声明数据源,作用是连接数据库的-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close"
    >
        <!--        set注入给DruidDataSource 提供数据库信息-->
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <!--mybatis主配置文件的位置
                   configLocation属性是Resource类型,读取配置文件
                   它的赋值,使用value,指定文件的路径,使用classpath:表示文件的位置
                -->
        <!--   <property name="configLocation" value="classpath:Mybatis.xml"/>===@Mapper代替
                @Mapper只是为我们找到dao的对应的mapper映射文件
                而创建dao接口的实现类并创建dao对象 是由下面的MapperScannerConfigurer执行的
                所以说 省略上面注释才是与@Mapper的功能是一样的
                 而下面的不能省略  下面的相当于是Mybatis的动态代理Sqlssion.getMapper创建接口的实现类
        -->
    </bean>
    <!--创建dao对象,使用SqlSession的getMapper(StudentDao.class)
       MapperScannerConfigurer:在内部调用getMapper()生成每个dao接口的代理对象。
   -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--指定包名, 包名是dao接口所在的包名。
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行
            一次getMapper()方法,得到每个接口的dao对象。
            创建好的dao对象放入到spring的容器中的。 dao对象的默认名称是 接口名首字母小写
        -->
        <property name="basePackage" value="com.bjpowernode.dao"/>
        <!--        如果有多个包那就依次写出来-->
    </bean>

    <!--    组件扫描器  扫描指定包中的注解  然后创建他们的对象-->
    <context:component-scan base-package="com.bjpowernode.dao"/>
    <context:component-scan base-package="com.bjpowernode.Service"/>
    <context:component-scan base-package="com.bjpowernode.domain"/>
</beans>

下面的组件扫描器 是为了扫描指定包中的注解。最后一个是实体类,我在测试类中测试插入的方法的时候需要调用ServiceStudent中的int insertStudent(Student student)方法,但是此时的我已经在ServiceStudent类中利用注解自动注入了student对象和它的注入值,所以在测试类的时候需要向insertStudent(Student student)方法添加方法所需要的参数值,但是已经注入到ServiceStudent,已经变成死的了,只能自己在测试类中重新手动创建student对象,这也是注解的坏处,虽然方便但是面对,经常需要改动的程序来说,还是选择配置文件吧。下面的两幅图就是我上面的文字描述:
在这里插入图片描述

所以将上图改为

在这里插入图片描述

可是这样改就摒弃了实体类的自动注入,在测试类中也就可以自己创建对象添加到数据库中了,现在才想起来前人们说的,实体类不要轻易的加注解,会很固定(但是如果想要更改,那么只需要在实体类中的Value注解赋其他的值就行),如果用户只有一个人 那么可以用,因为你加不进去啊,哈哈,注解限制了我们添加其他的用户。就像下图你再怎么new对象,你程序用的是上上图,那么始终调用的是上上图的student1自动注入(这样就只能通过改实体类中的注解Value来添加其他的用户了)。永远添加不了在下图new的对象。

测试类调用:
在这里插入图片描述

小插曲如何在idea中创建模板文件

在这里插入图片描述

第四章spring中的事务

代码不多,但是需要掌握和理解。
在这里插入图片描述
在这里插入图片描述

A、常用的两个实现类
PlatformTransactionManager 接口有两个常用的实现类:
➢ DataSourceTransactionManager:使用 JDBC 或 MyBatis 进行数据库操作时使用。
➢ HibernateTransactionManager:使用 Hibernate 进行持久化数据时使用。
B、 Spring 的回滚方式(理解)
Spring 事务的默认回滚方式是:发生运行时异常和 error 时回滚,发生受查(编译)异常时
提交。不过,对于受查异常,程序员也可以手工设置其回滚方式。
C、 回顾错误与异常(理解)
在这里插入图片描述
Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java 的 throw 语句抛出。

Error 是程序在运行过程中出现的无法处理的错误,比如 OutOfMemoryError、
ThreadDeath、NoSuchMethodError 等。当这些错误发生时,程序是无法处理(捕获或抛出)的,JVM 一般会终止线程。

程序在编译和运行时出现的另一类错误称之为异常,它是 JVM 通知程序员的一种方式。通过这种方式,让程序员知道已经或可能出现错误,要求程序员对其进行处理。

异常分为运行时异常与受查异常。

运行时异常,是 RuntimeException 类或其子类,即只有在运行时才出现的异常。如,NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException 等均属于运行时异常。这些异常由 JVM 抛出,在编译时不要求必须处理(捕获或抛出)。但,只要代码编写足够仔细,程序足够健壮,运行时异常是可以避免的。

受查异常,也叫编译时异常,即在代码编写时要求必须捕获或抛出的异常,若不处理,则无法通过编译。如 SQLException,ClassNotFoundException,IOException 等都属于受查异常。
RuntimeException 及其子类以外的异常,均属于受查异常。

当然,用户自定义的 Exception的子类,即用户自定义的异常也属受查异常。程序员在定义异常时,只要未明确声明定义的为 RuntimeException 的子类,那么定义的就是受查异常。
在这里插入图片描述
在这里插入图片描述
所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情况。如,A 事务中的方法 doSome()调用 B 事务中的方法 doOther(),在调用执行期间事务的维护情况,就称为事务传播行为。事务传播行为是加在方法上的。

事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。

四个事务隔离级别在下面有详细介绍

回答问题

1.什么是事务

讲mysql的时候,提出了事务。 事务是指一组sql语句的集合, 集合中有多条sql语句 可能是insert , update ,select ,delete, 我们希望这些多个sql语句都能成功,或者都失败, 这些sql语句的执行是一致的,作为一个整体执行。

2.在什么时候想到使用事务

当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。(比如转账,这边有记录记录收到,但是钱却没有打过来,为了保证数据库更新的一致性 所以我们此时就需要保证每一个数据库执行语句都能成功 此时在业务方法上增加事务)

在java代码中写程序,控制事务,此时事务应该放在那里呢?
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句

在这里插入图片描述

3.通常使用JDBC访问数据库, 还是mybatis访问数据库怎么处理事务

1.jdbc访问数据库,处理事务  Connection conn ; conn.commit(); conn.rollback();
2.mybatis访问数据库,处理事务, SqlSession.commit();  SqlSession.rollback();
3.hibernate访问数据库,处理事务, Session.commit(); Session.rollback();

4.在3的问题中事务的处理方式,有什么不足

1.不同的数据库访问技术,处理事务的对象,方法不同,
需要了解不同数据库访问技术使用事务的原理

2.掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务

3.处理事务的多种方法。

总结: 就是多种数据库的访问技术,有不同的事务处理的机制,对象,方法。

5.怎么解决不足

spring提供一种处理事务的统一模型, 能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。

使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理

使用spring的事务处理机制,可以完成hibernate访问数据库的事务处理。

在这里插入图片描述

6.处理事务,需要怎么做,做什么

spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了

1)事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
事务管理器是一个接口和他的众多实现类。
接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库—spring创建好的DataSourceTransactionManager

hibernate访问数据库----spring创建的是HibernateTransactionManager

怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用声明就可以了
例如,你要使用mybatis访问数据库,你应该在xml配置文件中
<bean id=“xxx" class="…DataSourceTransactionManager">

问题:上面的一段话??????怎么用注解代替呢

2)你的业务方法需要什么样的事务,说明需要事务的类型。
说明方法需要的事务:

    1)事务的隔离级别:有4个值。
	DEFAULT:采用 DB 默认的事务隔离级别。
	MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
	➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
	➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
	➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
	➢ SERIALIZABLE:串行化。不存在并发问题。

    2) 事务的超时时间(一般少用): 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
	  单位是秒, 整数值, 默认是 -1. 

    3)事务的传播行为(这是重点): 控制业务方法是不是有事务的, 是什么样的事务的。
	    7个传播行为,表示你的业务方法调用时,事务在方法之间是如何使用的。

		PROPAGATION_REQUIRED
		PROPAGATION_REQUIRES_NEW
		PROPAGATION_SUPPORTS
		以上三个需要掌握的

		PROPAGATION_MANDATORY
		PROPAGATION_NESTED
		PROPAGATION_NEVER
		PROPAGATION_NOT_SUPPORTED

a、 PROPAGATION_REQUIRED:(最常用的掌握这个就行)
指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。
如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther()方法时就是在事务内运行的,则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。如下图所示:
在这里插入图片描述
b、PROPAGATION_SUPPORTS(查询用的)
指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。
在这里插入图片描述
c、 PROPAGATION_REQUIRES_NEW
总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
在这里插入图片描述
3)事务提交事务,回滚事务的时机

 1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit
 
 2)当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
     运行时异常的定义: RuntimeException  和他的子类都是运行时异常, 例如NullPointException , NumberFormatException
  
 3) 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
    受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException

总结spring的事务

1.管理事务的是 事务管理和他的实现类
2.spring的事务是一个统一模型

  1)指定要使用的事务管理器实现类,使用<bean>
  2)指定哪些类,哪些方法需要加入事务的功能
  3)指定方法需要的隔离级别,传播行为,超时

你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。

当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。(比如转账,这边有记录记录收到,但是钱却没有打过来,为了保证数据库更新的一致性 所以我们此时就需要保证每一个数据库执行语句都能成功 此时在业务方法上增加事务)

解决方法:1.加事务 使用 Spring 的事务注解管理事务(掌握)

spring框架中提供的事务处理方案
1.适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

使用@Transactional的步骤:

1.需要声明事务管理器对象

因为是mybatis操作数据库 所以class是DataSourceTransactionManager

2.开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。

spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
    在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
   
	 @Around("你要增加的事务功能的业务方法名称")
	 Object myAround(){
       开启事务,spring给你开启
		  try{
		     buy(1001,10);
			  spring的事务管理器.commit();
		  }catch(Exception e){
         spring的事务管理器.rollback();
		  }
		 
	 }

3.在你的方法的上面加入@Trancational

@Transactional 的所有可选属性如下所示:

➢ propagation:用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。

➢ isolation:用于设置事务的隔离级别(默认值即可)。该属性类型为 Isolation 枚举,默认值为Isolation.DEFAULT。

➢ readOnly(一般不设置 太麻烦 网络等外界因素):用于设置该方法对数据库的操作是否是只读的(查询)。该属性为 boolean,默认值为 false。
➢ timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为
-1,即没有时限。

➢ rollbackFor:指定需要回滚的异常类。意思是发生指定的异常的时候需要回滚。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。

➢ rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。
当然,若只有一个异常类时,可以不使用数组。
➢ noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若
只有一个异常类时,可以不使用数组。
➢ noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空
数组。当然,若只有一个异常类时,可以不使用数组。
需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public
方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该
方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。
若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。

1.在spring配置文件需要声明事务管理器对象并添加注解驱动代码

 <!--使用spring的事务处理-->
    <!--1. 声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--连接的数据库, 指定数据源-->
        <property name="dataSource" ref="myDataSource" />
    </bean>

    <!--2. 开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象
           transaction-manager:事务管理器对象的id
    -->
    <tx:annotation-driven transaction-manager="transactionManager" />

注意添加注解驱动的时候是选择以tx结尾的驱动,tx结尾的才是事务

在这里插入图片描述

2.在你的方法的上面加入@Trancational并附上该有的属性

图1000:

在这里插入图片描述
rollbackFor里面的异常也可以是自己自定义的异常信息,表示执行方法时遇到异常,事务借助aop机制自动回滚,解决多条sql语句执行时出现结果不一致的情况。此时,发生回滚时,那么sql语句便不会向下继续执行,数据库里面的信息也不会发生更新的错误情况,也就是说注解的方法成功。
在这里插入图片描述
数据库为什么没有6和7呢,原因是在8是没有异常,成功执行所以数据库发生更新,而6,7都在执行时发生异常,事务进行回滚,将记录撤销了,又因为id设置的是自动增长,所以没有6,7。而执行一次没有异常就直接到8。

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

上图的属性都是默认值 所以可以在业务方法上只加入@Transactional注解本身就可以啦。与图1000对比。

解决方法:2.使用 AspectJ 的 AOP 配置管理事务(掌握)

适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

实现步骤: 都是在xml配置文件中实现。
1)要使用的是aspectj框架,需要加入依赖

<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-aspects</artifactId>
		<version>5.2.5.RELEASE</version>
	</dependency>
2)声明事务管理器对象(由于是mybatos连接数据库,所以用到的是DataSourceTransactionManager)



3) 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
4) 配置aop:指定哪些哪类要创建代理。
<!--声明式事务处理:和源代码完全分离的-->
    <!--1.声明事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="myDataSource" />
    </bean>

    <!--2.声明业务方法它的事务属性(隔离级别,传播行为,超时时间)
          id:自定义名称,表示 <tx:advice></tx:advice>之间的配置内容的
          transaction-manager:事务管理器对象的id
    -->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <!--tx:attributes:配置事务属性-->
        <tx:attributes>
            <!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
                name:方法名称,1)完整的方法名称,不带有包和类。
                              2)方法可以使用通配符,* 表示任意字符
                propagation:传播行为,枚举值
                isolation:隔离级别
                rollback-for:你指定的异常类名,全限定类名。 发生异常一定回滚
            -->
            <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
                       rollback-for="java.lang.NullPointerException,com.bjpowernode.excep.NotEnoughException"/>

            <!--使用通配符,指定很多的方法-->
            <tx:method name="add*" propagation="REQUIRES_NEW" />
            <!--指定修改方法-->
            <tx:method name="modify*" />
            <!--删除方法-->
            <tx:method name="remove*" />
            <!--查询方法,query,search,find-->
            <tx:method name="*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <!--配置aop-->
    <aop:config>
        <!--配置切入点表达式:指定哪些包中类,要使用事务
            id:切入点表达式的名称,唯一值
            expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象

            com.bjpowernode.service
            com.crm.service
            com.service
        -->
        <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>

        <!--配置增强器:关联adivce和pointcut
           advice-ref:通知,上面tx:advice哪里的配置
           pointcut-ref:切入点表达式的id
        -->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
    </aop:config>

在这里插入图片描述

第五章Spring 与 Web

web项目中怎么使用容器对象。

1.做的是javase项目有main方法的,执行代码是执行main方法的,
在main里面创建的容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);

2.web项目是在tomcat服务器上运行的。 tomcat一起动,项目一直运行的。

既然是web就需要加入jsp servlet依赖

<!-- servlet依赖 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- jsp依赖 -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
      <scope>provided</scope>
    </dependency>

当多次发送请求的时候,servlet就会创建多次对此applicationContext.xml里面的对象,每一次请求就创建一次对象,你想,垃圾回收器还没有来得及回收这些用掉的对象,请求又来了,又得再次创建这些对象,这样容易造成内存爆满的情况。
实际上呢,配置文件里面的对象是我们项目需要的所有对象,我们只需要创建一次就可以啦。
如下图所示:
在这里插入图片描述
需求:
web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。

怎么实现:
使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext

监听器作用:
1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener


 private WebApplicationContext context;
 public interface WebApplicationContext extends ApplicationContext


 ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象

把创建的容器对象,放入到全局作用域
 key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
       WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
 value:this.context

 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

weil使用上面的监听器我们需要再次添加一个依赖:

<dependency> 
<groupId>org.springframework</groupId> 
<artifactId>spring-web</artifactId> 
<version>5.2.5.RELEASE</version>
</dependency

在这里插入图片描述

创建监听器并使用监听器之后:监听器创建配置文件中的所有对象,然后将这些对象放在全局作用域中,现在我们使用框架给我们的方法来调用这些只需要创建一次的对象,在controllerservlet里面的代码:

 //使用框架中的方法,获取容器对象
        ServletContext sc = getServletContext();
        ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        System.out.println("容器对象的信息========"+ctx);

ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象

创建监听器:目的就是创建容器对象,创建了容器对象,就可以把spring配置文件中的所有的对象创建好了,继而用户发送请求时就可以直接使用对象了。

到此基本的spring框架知识整理完毕,这是我个人看视频的学习笔记,如有错误还请各位大佬多多指正-谢谢。
东西不多,但还是有一点点。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值