Spring框架学习
本文最后更新于:4 年前
这是SSM中Spring框架的学习,MyBatis记得复习嗷!!!
IoC学习
第一节课开始:
- Spring全家桶:- spring
- spring mvc
- spring boot
- spring cloud
 
- Spring核心技术:- ioc - 控制反转
- aop - 管理对象之间的关系
- ioc , aop能够实现模块之间,类之间的解耦合
 
- 文档获取:- spring官网
- 我们学的是Spring Framework
 
简介:
- 轻量: - 核心jar总共在3M左右,占有资源少,运行效率高,不依赖于其他的jar。
 
- 针对接口编程,解耦合: - ioc控制反转
 
- AOP编程的支持 
- 方便集成各种优秀框架(例如:Spring集成Mybatis) 
- 体系结构: 

- 框架怎么学:- 框架能干啥
- 框架的语法,需要一定的步骤支持
- 框架的内部实现,原理是什么
- 通过学习,可以实现一个框架
 
IoC控制反转:
- Inversion of Control
- 描述的想法是:- 把对象的创建,赋值和管理交给代码之外的容器实现,也就是对象的创建是由其他外部资源来完成的。
- 控制:- 创建对象,对象的属性赋值,对象之间的关系管理。
 
- 正转:- 开发人员主动使用new构造方法创建对象,开发人员主动管理对象。
 
- 反转:- 把原来开发人员管理,创建对象的权限转移给代码之外的容器来实现,由容器代替开发人员来管理对象,创建对象,给属性赋值。
 
- 容器:- 一个服务器软件,一个框架
 
 
- 为什么使用ioc:目的是减少对于代码的改动,也能够实现不同的功能。(实现解耦合)
Java中创建对象的方式:
- 构造方法 
- 反射 
- 序列化 
- 克隆 
- IoC:容器创建对象 
- 动态代理 
- IoC的体现: - Servlet就是一个体现,Servlet对象就是由服务器来创建的,不是我们手动创建的对象。所以Tomcat也被称为容器,里面存放的有Servlet对象,有Listener,Filter对象。
 
IoC技术实现:
- di:dependecty injection,依赖注入,IoC实现的一种方式。
- 只需要在程序中要使用的对象名称就可以了,对象的操作是由容器内部来实现的。
- Spring也是使用的di技术,底层本质上使用的反射机制来创建对象,因此可以通过名称来获得对象。
对象创建:
- 实现步骤: - 创建maven项目
- 加入maven依赖
- 创建类:- 接口和他的实现类
- 和没有使用框架一样,就是普通的类
 
- 创建spring需要使用的配置文件:- 申明类的信息,由spring创建管理
 
- 测试spring创建的对象
 
- Maven中依赖的添加(天坑): - 添加dependency的完整性
- Maven具体添加内容:
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46- <dependencies>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.11</version>
 <scope>test</scope>
 </dependency>
 
 <!-- https://mvnrepository.com/artifact/org.springframework/spring -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>
 
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>
 
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>
 
 
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context-support</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>
 
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-expression</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>
 
 
 </dependencies>
- 配置resources文件夹下的文件时: - 若没有Spring.xml这个选项:解决方法
- 配置文件中的内容:
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23- <?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">
 <!--告诉spring创建对象
 声明bean:就是告诉spring要创建某个类的对象
 id:对象的自定义名称,唯一值,Spring通过这个名称找到对象
 class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)
 Spring就会自动创建对象(使用对象的无参构造方法)并且放入到Map中,spring框架有一个map存放对象的
 一个bean标签声明一个对象。
 -->
 <bean id="someService" class="com.tuzi.service.impl.SomeServiceImpl"></bean>
 </beans>
 <!--
 spring的配置文件
 beans: 是根标签,spring把java对象称为bean
 spring-beans.xsd是约束文件
 -->- getBean()中参数是配置文件中你设置的id值域,通过这个值,可以获得对应的对象。
- 测试实例:
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- public void test02(){
 String config = "beans.xml";
 //ApplicationContext表示Spring容器,可以通过这个容器获取对象
 //classpath表示从类路径中加载spring的配置文件,获得这个全局变量
 ApplicationContext temp = new ClassPathXmlApplicationContext(config);
 //执行上面这条语句的时候实际上就创建了对象的啦。
 
 //获得全局变量中你要的那个对象(通过id获取)
 SomeService service = (SomeService) temp.getBean("someService");
 service.doSome();
 }
- 创建全局Map对象的时候,所有你声明在spring的配置文件中的对象实际上都配置好了嗷!!! 
对象方法:
- getBeanDefinitionNames():获取对象的名字数组
- getBeanDefinitionCount():获取对象数目
创建非自定义类的对象:
- 创建存在的某个类的对象(不是自己写的类,已经存在的)
- 当然是可以创建对象的,只要别人写好的类,获得对应的类,就能获得对应的对象。
- 你可以导入系统中某些块儿,如Date类的绝对路径,Spring就能够创建这个Date类。
- 记住,Spring创建对象时候使用的默认是无参数的构造方法。
Spring给Java对象属性赋值:
Set方式赋值
- 实现方式: - 使用标签和属性完成,基于xml的di实现。
- 使用Spring中的注解,完成属性赋值,叫做基于注解的id实现。
 
- di语法分类: - set注入:Spring调用set方法,80%都是使用这种。
- 构造注入:Spring中调用类的参数构造方法,创建对象,在构造方法中完成赋值。
 
- 配置文件的默认名字: - applicationContext
 
- Spring中规定Java基本数据类型和String都是简单类型 
- set注入: - Spring中调用类的set方法,可以在set方法中完成赋值
- 具体实操: 
- Spring就会自动根据这些信息去给对应的属性赋值。
 
- 注意这里的value必须都是用字符串来表示的。
 
 
- 命名规则中一个属性就应该对应一个set和一个get。如果你的类中没有Set方法,当前的赋值行为是不可以正常执行的。必须要有Set方法嗷。 
- Spring只负责执行对应的Set赋值方法,具体方法里面是如何执行,甚至方法里面赋值与否,是由你来决定的嗷!!! 
- Set过程: - Spring调用无参构造构造对象
- Spring使用对应的set方法来实现属性的赋值
- 就算没有这个属性,只要符合设值注入的规则,Spring都可以正常执行嗷,只看有没有对应的Set方法!!!本质上就是调用Set方法而已,不管有没有这个属性的。
 
- 不管什么属性,这里赋值的使用用的都要加上引号,这是xml文件的规则。 
- 不管是不是自定义类,只要有Set方法,就可以调用Set方法嗷!!! 
引用类型Set赋值:
 
 
- value + ref
构造注入方式:
- 有参构造,构造的时候注入嗷!!!
- constructor-arg标签,属性:- name:形参名
- index:从左往右0,1,2的顺序
- value:形参类型是简单类型的
- ref:形参类型是应用类型
 
name注入:
 
- 这里的顺序很智能,上下的bean顺序没有必然的上下顺序嗷。
index注入:

- constructor的上下顺序也可以调整位置的嗷。
- 省略index,直接给value也可以,不过这个时候上下的顺序就不可以换咯!!!
File构造注入:
- 如果知道File的话,就可以构造注入了嗷。
结论:
用name可读性更高,推荐用name嗷。
JUnit简介:
- 单元测试,单独测试不同的方法
- 首先需要加入JUnit的依赖
- 测试方法的定义:- 首先应该是public方法
- 没有返回值,void
- 方法名称自定义,建议名称是test+你要测试方法的名称
- 方法没有参数
- 方法上面加入@Test,这种方法是可以单独执行的,不用main方法
 
第一节课总结:
什么是Spring:
- 一个框架,核心技术是ioc和aop,实现解耦合。
- Spring是一个容器,其中存放的是Java对象,我们将对象放入到容器中。
- 核心思想:想用啥你就在配置文件中声明啥就好啦!!!
- 值是可以在配置文件指定关系时(如ref)动态替换的,降低了类之间的耦合度。
怎么使用Spring:
- 项目中用到的对象放入到容器中
- 让容器完成对象的创建,对象之间的管理
- 我们程序从容器中获取要使用的对象
什么样的对象放入容器:
- dao , service , controller , 工具类
- Spring中对象默认是单例的,不能有重名的对象
什么对象不放入容器:
- 实体类对象,实体类数据来自数据库。 
- Servlet 
- Listener 
- Filter 
- 上面这些是Tomcat中的,不要放入Spring中 
把对象放入容器中:
- xml配置文件
- <bean>标签
- 注解
使用Spring的步骤:
- 加依赖
- 创建类
- 创建Spring配置文件,使用bean声明对象
- 通过ApplicationContext接口和ClassPathXmlApplicationContext的方法getBean()
第二节课开始:
自动注入:
- 引用类型有效,针对某些规则对于引用类型赋值,不用你再给引用类型赋值。 
- 规则: - byName: - 按照名称注入,java类中引用类型的属性名和spring容器中bean的id一样。且数据类型是一致的,就可以赋值。
- 语法:
 - <bean id="xx" class="yyy" autowire="byName">
- byType: - Java类中引用类型的数据类型和spring中bean的class属性是同源关系,这样的bean可以赋值给引用类型。 
- 同源的类型: - java类中引用类型和bean的class是一样的。
- java类中引用类型和bean的class是父子类关系。
- java类中引用类型和bean的class是接口实现类关系。
 
 
 
- 以上多种都存在的时候,会抛出异常的,只有single matching的时候才能够正确赋值。 
多配置文件的方式:
- 项目规模比较大的时候,使用多个配置文件
- 优势:- 每个文件的大小会比一个文件小很多
- 避免多人竞争带来的冲突。- 比如你的项目有多个模块,一个模块一个配置文件。不同人就可以操作不同的配置文件。
- 也可以按照类的功能划分,比如操作数据库的就单独一个配置文件,不同人也是操作不同类型的类的配置文件。
 
 
包含关系的配置关系:
- 有一个主配置文件,只包含其他文件,不包含bean对象,说白了就是用来处理关系的。

- 注意一下这里的classpath,指的是从编译完成的classes目录下找对应的class,所以要注意文件的目录结构。
- 先加载总的文件,总的文件根据路径,把所有相关的文件都加载进来成为一整个文件,和原来的没啥区别!!!
- 在包含的配置文件中,可以使用通配符(*:表示任意字符): 
- 主的配置文件名称不能够在通配符的范围内,不然就会产生“死循环”。
- 使用通配符的文件必须要放在同一个目录中,不然就会失败。
 
注解的使用:
- 注解本身是一个类嗷!!! 
- 基于注解的di: - 基于注解完成Java的床创建,属性赋值。
 
- 使用注解的步骤: - 加入maven的依赖:spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖。使用注解必须加入aop依赖
- 类中加入spring注解(多个不同功能的注解)
- 在spring的配置文件中加入一个组件扫描器的标签,说明注解在你的项目中的位置。
 
- 学习的注解: - component
- respotory
- service
- controller
- value
- autowired
- resources
 
- 实现步骤: - 加入依赖
- 创建类,加入注解
- 创建spring的配置文件
- 使用注解创建对象
 
Component:
- value就是对象的名称,也就是bean的id。
- value的值是唯一的,创建的对象在整个Spring容器中就只有一个。
- 注解位置:在类的上面。
- 添加了注解之后,配置文件中还要添加component-scan标签,扫描遍历base-package所指定的包,把包中和子包中的所有类,找到类中的注解,按照注解创建对象或给属性赋值。
- 加入component-scan标签后,配置文件的变化:- 加入一个新的约束文件spring-context.xsd
 
- 默认调用的也是无参构造方法

- 其中第二种最常用,Spring中和@Component功能一致,创建对象的注解还有: - @Repository:用在持久层上面的注解
- @Service:用在service的实现类上面,创建service对象,做业务处理的
- @Controller:用在控制器上面,创建控制器对象的。
 - 以上三个注解的使用语法和Component一样的,但是他们各自还有额外功能。这三个注解是给我们的项目对象分层的。 
- 什么时候使用Component呢? - 不是上面的三种就用Component就好了嘛
 
指定扫描多个包:
- comonent-scan使用多次去扫描
- 或者使用(;或者,)分隔多个包名
- 指定父包

简单类型赋值:
- 使用Value注解 
- value是string类型的,表示简单类型的属性值 
- 位置: - 在属性定义上面,无须set方法,推荐使用
- 在set方法上面
 
- 可以省略Value中的value,这是项目中的常用方式,非常方便直观嘛。 
- 一般都是放在属性之上,要注意哈,@Component之类的注解是不能少的,不然对象根本创建不出来好吧。 
- 本质上Spring内部维护了一个Map,通过你给key的值返回对应的value(对象)给你嗷!!! 
引用类型赋值:
- Autowired:Spring框架提供的注解,实现引用类型的赋值。支持byName和byType
- @Autowired默认使用的是byType自动注入。
 
- 默认搜索容器中的School对象并且赋值给School对象。
- 不管你用注解也好,bean标签也好,都本质上是去创建对象!!!注解是和配置文件等价的嗷!!!
- 如果使用的是byName的方式,需要做的是:- 在属性上面加入@Autowired
- 在属性上面夹入@Qualifier(value=”bean的id”)
- 注意是上面两个要同时加入到属性上面嗷!!!最好按照上面这个顺序来写嗷!!!
 
Required属性
- required = true是默认的,表示引用类型赋值失败时报错,这个required是在@Autowired后面的属性。假的话,不报错哦,引用类型赋值为Null而已。
- 设置为真比较合适,可以尽早暴露出来程序的错误,假的话有问题可能显示不出来嗷。
Resource:
- JDK中的注解,Spring框架提供了对于这个注解的功能支持,可以使用它给引用类型赋值,也是自动注入原理,支持两种模式,默认是byName。
- 位置:- 在属性定义的上面,无须Set方法,推荐使用。
- 在Set方法上面
 
- 过程:- 先使用byName自动注入
- 如果byName失败了,这个时候再使用byType
 
- 如果只想使用byName怎么办???- 增加一个属性name
- name的值是bean的id
- @Resource(name="mySchool")
 
Summary:
- 经常改的就用配置文件(非常灵活,代码和它的值是分开的,解耦合了嗷!!!缺点是费时费力,灵活的话代码就低嘛,而且代码和值分开不容易查看)
- 不经常改的就用注解(很快很方便,生产力很高,代码和注解在一起也方便查看嗷!!!缺点是灵活性就差一点,注解的方式现在是一种趋势嗷。而且注解和代码混在一起,代码就有点难顶。)
- 注解为主,配置文件为符。
属性配置文件的导入和使用:

- 先读入文件的内容

- 导入配置文件之后就可以用占位符来通过key获取到value
注解总结:
- 常用注解:- @Component , 创建对象
- @Repository , 创建dao对象,用来访问数据库的
- @Service,创建service对象,处理业务逻辑的,可以有事务功能
- @Controller , 创建控制器对象,接收请求,显示处理结果的。
- @Value,简单类型的赋值
- @Autowired,Spring框架中引用对象的赋值解释,
- @Resource,JDK中的注解,自动注入给引用类型赋值
 
- 注解使用:- 加入依赖:spring-context
- 在类中加入注解
- 在spring的配置文件中,加入组件扫描器
 
- 自动注入:- 由spring根据某些规则给引用类型完成赋值
- byName根据名称注入,属性名和bean中的id一样,类型一样的赋值
- byType根据类型注入,有三种方式匹配方式(与class是同源关系的)
 
IoC的解耦合解的是啥?
- 实现业务对象之间的解耦合,例如service和dao对象之间的解耦合,关系变得比较松散。
- 对象的赋值通过配置文件来赋值,由容器spring来负责对象的创建和对象之间关系的管理,类与类之间没有本身直接的联系,这样就起到了解耦合的作用。
AOP学习
- 动态代理:- 程序在整个运行过程中根本就不存在目标类的代理类,目标对象只是由代理生成工具在程序运行时由JVM根据反射等机制动态生成的。代理对象和目标对象的代理关系在程序运行的时候才确立。
- 原有程序不改变的情况下给程序增加功能。(功能增强)
 
- 方式:- JDK动态代理:- JDK的Proxy
- JDK的Method
- JDK的InovcationHandler
- 要求目标类必须实现接口(必须有接口)
 
- CGLIB动态代理:- 原理是继承,因此类不能够是final类,否则就无法实现这种动态代理的原理。
- 优势:- 效率高
- 要求低
 
 
 
- JDK动态代理:
动态代理小例子
- 在不修改原有代码的情况下,实现功能增强。执行过程中创建代理对象,来增强功能。
- 步骤:- 创建目标类
- 创建接口实现类,给这个类实现增加的功能
- 使用jdk中的proxy,创建代理对象,实现创建对象的能力。
 
- 如果想要只为某些方法来添加动态代理,可以在动态代理中采用判断方法的技巧,因为动态代理中是知道你的调用方法的名字的,通过名字可以进行分类从而实现分别处理。
第三节课开始:
什么是AOP:
- 底层本质就是动态代理,只不过进行了一种规范化处理而已。 
- 实现方式: - JDK:- 要求目标类必须实现了接口
 
- CGLIB:- 原理是继承,通过目标类的继承来创建子类
 
 
- JDK:
- 动态代理的作用: - 在目标类源代码不改变的情况下去增加功能。
- 减少代码的重复。
- 专注业务逻辑代码。
- 解耦合,让业务功能和非业务功能分离。
 
- 切面定义: - 面向切面编程,和上面一样有两种方式。 
- 动态代理实现步骤和方法都定义好了,让开发人员用统一的方式来使用动态代理。 
- 切面: - 给你的目标类添加的功能就是切面。特点:非业务方法,一般都是可以单独使用的。
 
- 考虑的点: - 找出切面
- 合理安排切面执行的事件(目标方法前后)
- 合理安排切面执行的位置(哪个类的哪个方法)
 
 
- JoinPoint定义:(单个) - 连接点,连接业务方法和切面的位置,某类中的业务方法
 
- Pointcout:(多个) - 切入点,多个连接点方法的集合
 
- 目标对象: - 给哪个类的方法增加功能,这个类就是目标对象
 
- Advice: - 通知是用来表示切面的功能执行的事件
 
- 切面的三要素: - 切面的工作代码
- 切面的执行位置(Pointcut)
- 切面的执行时间
 
 
AOP的实现:
- 技术实现:- spring在内部实现了aop的规范,可以做aop,主要在事务处理使用aop。项目开发中很少使用spring的aop实现,因为spring的aop比较笨重
- aspectJ:开源的aop的框架,实际开发中用到最广泛的。spring框架中实际上已经继承了这个框架,通过spring就能使用aspectJ的功能
 
- 实现aop的两种方式:- xml的配置文件
- 使用注解,我们在项目中做aop功能,一般都使用注解,aspect有5个注解。
 
aspectJ的使用:
执行时间
- 切面的执行时间,执行时间在规范中叫做Advice通知(增强)。在aspectJ在框架中使用注解来表示的。
- 五个注解:- Before
- AfterReturning
- Around
- AfterThrowing
- After
 
- 也可以使用xml配置文件中的标签。
执行位置
- 使用的是切入点表达式
 
- 最常用就是用下面的红色的那两个就够用的。
- 符号使用:- * 0至多个任意字符。
- .. 用在方法参数中,表示任意多个参数。用在包名后,表示当前包以及其子路径。
- + 用在类名后,表示当前类和其子类。用在接口后,表示当前接口以及其实现类。
 
- 例子:

- 小技巧:- 找到含有service包的全部类
- execution(* *..service.*.*(..))
 
aspectJ实现aop基本步骤:
- 新建maven项目
- 加入依赖:- spring
- aspectj
- 单元测试
 
- 创建类:接口和它的实现类。要做的是给类中的方法增加功能。
- 创建切面类(普通类):- 在类的上面加入@Aspect
- 类中定义方法,就是切面要执行的功能代码,在方法上面加入aspectj中的通知注解,例如@Before。还需要指定切入点表达式。
 
- 创建Spring的配置文件:声明对象,把对象给容器统一管理:标签或注解的方式。- 声明目标对象
- 声明切面类对象
- 声明aspectj框架中自动代理生成器标签:用于代理对象的自动创建功能
 
- 创建测试类,从spring容器中获取目标对象(实际上就是代理对象),通过代理执行方法实现aop的功能增强。
新项目Maven要添加的依赖
| 1 |  | 
创建目标类
- 接口和接口实现类
- 其中接口实现类即为我们的目标类,接口是给反射使用的
创建切面类

@Before:
- 前置通知注解,强调了注解发生的时间。
- 它有一个属性叫做value,是切入点表达式,表示切面的功能和执行的位置。
- 特点:- 在目标方法之前执行
- 不会改变目标方法的执行结果
- 不会影响目标方法的执行
 

创建配置容器配置文件
- 在Spring中注册对应的目标类和切面类。
- 自动代理生成器,会将容器中所有的目标对象都找到,一次性都生成代理对象
- 配置文件内容:
| 1 |  | 
测试是否正确:

- 底层本质上用的还是JDK的动态代理。
- 加载配置文件的时候,实际上在扫描到aop那一条的时候才开始找@Aspect,最终生成代理类。相当于和之前相比,多了一步去生成代理而已,其他没啥区别。
切面类如果出错
- 如果找切面类中写错了,目标对象的方法找不到
- 切面类就和没有一样,直接执行目标类本身的功能。
AOP作用:
- 想补充功能但是自己没有源代码
- 给项目中的多个类增加一个相同的功能
- 给业务方法增加事务,日志输出
切面类中的参数:
JoinPoint:
 
- 注意这个参数是大写的嗷!!!
- JoinPoint必须位于所有参数中的第一个位置上嗷!!!
- 这个参数是放在方法里面,方法里面的参数是限定的嗷!!!
 
切面类种类:
@Before:
- 前置通知,在对应的类执行之前先执行函数中的内容
- 参数:- value 切入点表达式
- JoinPoint
 
@AfterReturning:
- 这个方法是有参数的,推荐使用Object,参数名自定义。 
- 属性: - value 切入点表达式
- JoinPoint
- returning 自定义表达式,表示目标方法的返回值,自定义变量名必须和通知方法的形参名一致。
 
- 位置:方法定义上面 
- 特点: - 目标方法之后执行
- 可以获取目标方法的返回值,根据返回值处理不同的功能
- 可以修改这个返回值
 
- 例子: 
- 定义的方法中有返回值的话,可以才可以获得返回值哦。 
- 切面类甚至可以悄悄咪咪修改一波返回值,但是在后置通知中修改返回值对于程序的执行是没有影响的嗷QAQ!!!不对不对!!!引用类型是可以变的嗷!!!但是我的方法都执行完了,又没啥影响orz。 
- 后置通知的执行: - Object res = doOther();
- myAfterReturing(res);
 
@Around:
- 定义格式:- public
- 必须有一个返回值,推荐使用Object
- 方法名称自定义
- 方法有参数,固定的参数ProceedingJoinPoint
 
- 属性:- value
 
- 特点:- 功能最强的通知(可以在前后都增强功能)
- 控制目标方法是否被调用执行
- 可以修改执行结果,影响最后的调用结果
- 等同于jdk中的动态代理,InvocationHandle接口
 
- ProceedingJoinPoint就等同于Method,执行目标方法的
- 返回值:就是目标方法的执行结果,可以被修改嗷
- 具体例子:

- 控制是否执行目标函数的功能的例子: - 结合JoinPoint一起使用嗷!!!
- 发现ProceedingJoinPoint是继承于JoinPoint的!!!可以当作JoinPoint来使用。
- 例子:
  - 通过参数卡死了方法,不符合条件就不能够执行嗷!!!
 
- 修改目标方法的执行结果,它返回的结果才是调用代理类所获得的最终结果,换句话说,对于结果进行了加工处理。 
- 经常用于事务处理,目标方法之前开启事务,目标方法之后提交事务。 
@AfterThrowing
- 异常通知
- 格式:- public
- 没有返回值
- 方法名称自定义
- 方法有一个Exception,如果还有的话是JoinPoint
 
- 属性:- value 切入点表达式
- throwing 自定义变量,表示目标方法推出的异常对象,变量名必须和方法的参数一样
 
- 特点:- 在目标方法推出异常的时候执行
- 可以做异常的监控程序,监控方法是不是有异常。如果有异常可以发送邮件,短信等进行通知
 
- 例子:
- 没有异常就不执行,发生了异常可以进行异常通知。
- 本质上是try加上catch来捕获异常的那种用法嗷!!!
@After
- 最终通知
- 格式:- public
- 无返回值
- 方法名称自定义
- 方法没有参数,如果还有的话是JoinPoint
 
- 特点:- 总是会执行
- 在方法之后执行
 
- 一般是用于做资源清除工作的
- 就算遇见了异常也会正常执行嗷!!!
- 例子:
- 实际上就类似于try…catch…finally中的finally后的代码
@PointCut
- 辅助的功能注解 
- 切入点表达式共有的,引用又长又臭,顶不住。如果有多个可复用的切入点表达式,用@PointCut 
- 属性: - value , 切入点表达式
 
- 特点: - 如果@PointCut定义在一个方法上面,这个方法名称就成为了切入点表达式的别名。
- 其他的通知中,value属性就可以使用这个方法的别名
 
- 例子: 
- 记得上面这个要加上括号哈,mypt()本质上就是一个辅助功能的无代码方法,帮助我们定义切入点用的。这个方法一般是私有的哈,上面这个改一下,它不需要被外界调用哇!!! 
动态代理种类:
- 如果目标类实现了接口,这个时候默认使用的就是JDK的动态代理。
- 没有接口的话默认使用的是cglib来实现动态代理。
- 有接口其实也可以使用cglib来实现动态代理的:

Spring集成MyBatis:
- 使用到的技术是IOC,可以把MyBatis框架中的对象交给spring统一创建,开发人员从spring中获取框架。开发人员就不用同时面对两个或者多个对象了,就面对一个spring就可以了。
MyBatis的使用:
- 定义dao接口
- 定义mapper文件
- 定义mybatis的主配置文件 mybatis.xml
- 定义dao的代理对象,Student dao = SqlSession.getMapper(studentDao.class)
- 调用接口的方法即可。
要使用dao对象,需要使用getMapper()方法,怎么使用getMapper方法呢?
- 获取SqlSession对象,需要使用SqlSessionFactory的openSession()方法。
- 创建SqlSessionFactory对象,通过读取mybatis主配置文件就能够创建SqlSessionFactory对象。
需要SqlSessionFactory对象,使用Factory就能够获取SqlSession,有了SqlSession就能有dao,目的就是获取dao。Factory的创建需要去读取主配置文件。
主配置文件信息:
大型项目的时候,之前学的主配置文件中的连接池是不够用的,性能太弱了,因此使用其他的连接池,也交给spring来处理。会使用一个独立的连接池类来替换mybatis自己带的,把连接池类也交给spring创建。
=========================================================================================================================================================================================
- 需要让spring创建以下对象- 连接池类对象,使用阿里的druid连接池
- SqlSessionFactory对象
- 创建出dao对象
 
- 现在的学习阶段使用xml的bean标签,而且这几个是固定的嗷!!!
具体集成步骤:
- 新建Maven项目
- 加入Maven依赖:- Spring依赖
- MyBatis依赖
- mysql驱动
- spring的事务的依赖
- mybatis和spring集成的依赖:mybatis官方提供的,用来在spring项目中创建mybatis的SqlSessionFactory,dao对象的。
 
- 创建实体类
- 创建dao接口和mapper文件
- 创建mybatis主配置文件
- 创建Service接口和实现类,属性是dao
- 创建spring的配置文件:声明mybatis的对象交给spring创建:- 数据源
- SqlSessionFactory
- Dao对象
- 声明自定义的service
 
- 创建测试类,获取Service对象,通过service调用dao完成数据库的访问。
Maven依赖:
| 1 |  | 
除此之外,build标签中也需要加入对应的配置和依赖:
| 1 |  | 
MyBatis配置:
- Dao中的接口和xml文件照着写就好
- 主配置文件由于不用自带的POOLED了,可以将environment全部删掉
逻辑理清:
这里的service层实际上就是起到了调用Dao层的对象处理业务的作用。
Druid的使用:
- 配置可以看官网的配置说明。 
Druid的对象创建:
| 1 |  | 
- 这个代码相对固定
SqlSessionFactory的创建:
| 1 |  | 
- 这个代码相对固定
Dao对象的创建:
| 1 |  | 
- 自动可以创建所有的dao对象,名字为接口名的首字母小写,这样就可以拿到对应的接口对象辽。
Service对象的创建:
- Service本质上是对于Dao层的一个封装,所以Service接口里面包含的方法和Dao里面的是有关系的,Dao提供的是最基本的服务,Service则提供复杂的业务逻辑,调用Dao中的功能来实现某些操作,例如给Service一个对象,它先判断你给的对象对不对,对的话再调用底层的Dao来将数据给数据库。Service的接口和实现类最好分开,实现不同的业务功能。
- 除此之外,Service为了使用Dao的代理类,实现类中包含了Dao对象以此来使用Dao层提供的服务功能。
| 1 |  | 
Spring整合之后:
- MyBatis被Spring整合之后,事务变成了自动提交的嗷!!!
属性配置文件保存信息:
- 和之前一样,将配置文件单独写,然后在spring主配置文件中导入信息即可。
- 如何在applicationContext导入配置文件:- <context:property-placeholder location="classpath:jdbc.properties">
 
- 这个配置能够使得spring知道这个配置文件的存在嗷!!!

- 又解耦合啦,多快乐嗷!!!
- 注意下:

老师这里说location里面要加上个classpath,但是我不加貌似也没啥问题嗷orz。
复习AOP
- 六种通知要再去复习哈: - Before
- AfterReturning
- Around
- AfterThrowing
- After
- PointCut(辅助)
 
- 代理的使用方式: - 目标类有接口 - jdk代理
- 目标类没有接口 - cglib代理
- 有接口也可以强制使用cglib代理
 
- 切入点表达式 
- 使用情况: - 增加功能
- 多个类增加相同功能
- 事务,日志输出
 
整合Mybatis:
- 使用IoC核心技术,将MyBatis也交给Spring来控制,spring是容器,容器存放你项目中要使用的各种对象。
- 交给Spring的Mybatis对象:- 数据源DataSource(Druid)。(它本质上实现了JDBC中的创建连接对象)
- SqlSessionFactory,使用的SqlSessionFactoryBean在内部创建的SqlSessionFactory。(它利用上面的连接对象,创建了会话的对象工厂,也就是创建了对象)
- Dao代理对象,使用MapperScanConfigure,在类的内部,调用getMapper,创建接口的Dao对象。(它利用了上面的会话对象,创建了具体的sql语句和returnType)
 
整合Mybatis基本语法结束
事务:
什么是事务:
- 一组sql集合,要么都成功,要么都失败
什么时候用到事务:
- 当操作涉及到多张表,或者是多个sql语句的insert , update , delete 。 需要保证这些语句都能成功才能完成我的功能,否则都失败,保证操作符合要求。 
- 事务放在哪儿呢? - 业务方法中才可能需要多个dao方法,调度多种方法实现事务,因此需要处理事务。
- 一般在Service类中使用
 
- 通常使用JDBC , MyBatis如何实现事务: - JDBC: Connection conn ; conn.commit() ; conn.rollback() ;
- MyBatis:SqlSession.commit(); SqlSession.rollback();
 
- 上面处理方式不足: - 不同的数据库访问技术,处理事务的对象方法不同,需要了解不同数据库访问计数使用事务的原理。
- 掌握多种数据库中事务处理逻辑,什么时候提交事务,什么时候回滚事务
- 处理事务的多种方法
- 总结:技术太多,太乱太杂
 
- 怎么解决不足? - spring提供了一种处理事务的统一模型,能使用统一步骤,方式完成不同数据库的事务处理。
 
Spring操作数据库事务示意图:

- 处理事务需要怎么做,做什么- 将事务使用的信息提供给spring就可以了
- 内部提交,回滚事务的事务管理器,代替你实现事务
- 是一个接口和它的众多实现类。
 
- 接口:PlatformTransactionManager,定义了事务的重要方法 commit 和 rollback。实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
- mybatis访问数据库的—–spring创建好的DataSourceTransactionManager
怎么使用:
基本用法:
- 告诉spring你使用的是那种数据库访问计数,怎么告诉spring? 
- 声明数据库访问计数对于事务管理器实现类,在spring中用bean声明就可以了 
- 例如mybaits —> 
- 你的业务方法需要什么样的事务呢?需要说明事务的类型 
- 说明书屋类型的方法包括: - 事务隔离级别
  
- 以ISOLATION_为开头的,官方文档中可以通过api找得到。 
 - 事务的超时时间:
 - 一个方法的最长执行时间。如果方法执行时间超过了时间,事务就回滚。时间是秒,默认是-1。难于控制,一般用默认的就可以了。
 - 事务的传播行为
 - 控制业务行为是否有事务 
- 七个传播行为:  
- 前三个掌握就行了。
 
- 第一个是REQUIRED,是默认值: - 指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中。没有就新建一个事务。
- 例如在调度的过程中,你的主程序属于一个事务当中,你调度的方法同时也需要事务,这个时候这个方法就会加入到当前事务中执行。
- 例如在调度的过程中,你的主程序不属于一个事务当中,你调度的方法同时也需要事务,这个时候这个方法就会创建一个新事务并在事务中执行。
  
- 第二个是supports: - 有事务,无事务都可以哈
- 例如查询操作就符合这种条件
 
- 第三个是requires_new: - 每次自己都要新建一个事务,不用别人的
- 每次执行到都会挂起别人的事务
 
 
提交,回滚事务的时机:
- 提交:- 任务执行成功,没有异常抛出,执行完毕后spring自动提交事务。 
- 抛出运行时异常或ERROR,spring执行回滚,调用事务管理器的rollback。RuntimeException和它的子类都是运行时异常,例如NullPointer… , NumberFormat…等等 
- 抛出非运行时异常,主要是受查异常,提交事务。 - 受查异常时你在代码中必须处理的遗产给,比如IOException , SQLException等。 
 
总结:
- 事务管理器和它的实现类,使用 
- 指定哪些类,哪些方法需要加入事务的功能 
- 指定事务的隔离级别,传播行为,超时等 
- 你需要告诉spring你项目中类的信息,方法的名称和方法的事务传播行为就可以了。spring帮你做嗷!!! 
事务实例:
- 这里动力节点的例子讲的非常好,自己回去再看几遍嗷!!!电商销售平台实例 
- 处理事务的方案: - 注解方案: - 适用于中小项目的解决方案:- 使用注解@Transactional注解增加事务
- 这个写在public方法上面
- spring框架自己用aop实现给业务方法增加事务的功能。
- 我们可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等。
 
 
- 适用于中小项目的解决方案:
- 大型项目: - AspectJ的AOP配置管理事务。
- 大量配置事务,使用框架在spring配置文件中声明类,方法需要的事务,这种方法使得业务方法和事务配置完全分离。
- 实现步骤:都是在xml配置文件中完成的。
 
 
@Transactional
- 使用@Transactional的步骤: - 声明事务管理器对象。 - 开启事务注解驱动,告诉spring,我要使用注解的方式管理事务。spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。spring自动帮助你开启和关闭事务,本质上就是用的@Around方式来帮助你开启和关闭事务。
  - 方法上面还需要加上注解。
 
- 事务实操:  
- 第二步有一个易错点哈:
 
- 第二步实操:
 
 
 
- 上面的完成之后,就可以在实现类中写注解来使用事务啦!!! 
- 实现类中的注释实例: 
- 如果只添加@Transactional的话,结果和上面这个是一样的,因为上面这一坨定义就是默认值。如果需要个性化配置的话,单独去配置属性就好了嗷!!! 
- roollbackFor的处理逻辑: - 判断异常是否在rollbackFor中,如果在的话一定回滚。
- 如果抛出的异常不在rollbackFor的列表中,spring会判断异常是不是RunTimeException的异常,如果在的话也回滚
 
- 默认情况下大多就直接写了个注解就够了嗷,不需要额外配置了嗷!!! 
AspectJ使用配置文件的方式
- 使用方法: - 加入依赖
 - 1 
 2
 3
 4
 5- <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-aspects</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>- 声明事务管理器对象
- 声明方法需要的事务类型(配置方法的事务属性):- 隔离级别
- 传播行为
- 超时
 
 
- 下面是操作实例:  
- 声明事务管理器对象:
 
- 有坑!!!
 
- 声明事务属性(隔离级别,传播行为,超时时间):- 超时时间一般用默认的不用动嗷!!!
- 配置图片:
 
- 少了一个查询补上嗷!!!
 
 
- 配置顺序就是从上往下哈,优先级就是看详细不,越详细优先级越高嗷!!!!
- 问题,这个名字不是全限定名称啊,很多重名的咋办捏??? -> 还要别的来配置嗷!!!
- 配置一个aop类,配置切入点表达式,配置哪些包中的类要应用事务(相当于上面定义了事务的规则,下面定义这一套的规则用于哪些类,哪些包中)
 
- 上面就用上了哟~
 
Web环境中怎么使用容器
实现步骤:
- 环境: - 创建maven web项目
- 加入依赖:- servlet依赖
- jsp依赖
 
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>javax.servlet-api</artifactId>
 <version>4.0.1</version>
 </dependency>
 
 <dependency>
 <groupId>javax.servlet.jsp</groupId>
 <artifactId>jsp-api</artifactId>
 <version>2.2.1-b03</version>
 </dependency>
 </dependencies>- 再拷贝添加spring等依赖。
- 创建jsp发起请求。
- 创建Servlet,接收请求参数,调用Service,调用dao完成功能。
- 创建一个jsp显示结果页面。
 
- Servlet提升版本: - 默认生成的web.xml中版本太低了,这儿要把版本生成为4.0,有个小技巧,你要康康下面这个视频嗷!!!
- 提升版本的方法
 
- 无非就是把对于spring的操作放入到servlet的处理逻辑中而已,没啥区别 
- 去看我写的spring-mybatis-webapp,这样会比较方便,我写的没啥问题了。 
- 一些问题: 

- 容器创建只需要一次就行,不然太浪费资源了呀!!!然后你就要去看看,这个时候可以就会用到全局对象,把容器对象放入全局对象中,高效利用资源。
监听器:
- 负责将容器对象放入全局作用域当中,避免反复创建容器浪费资源。 
- 全局作用域对象为ServletContext 
- 监听器可以自己创建,也可以使用框架中提供的ContextLoaderListener 
- 如何使用ContextLoaderListener: - 添加maven依赖
 - 1 
 2
 3
 4
 5- <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-web</artifactId>
 <version>5.2.5.RELEASE</version>
 </dependency>- web.xml文件中注册监听器ContextLoaderListener
 - 1 
 2
 3- <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>- 监听器被创建对象之后,会读取/WEB-INF/applicationContext.xml,why?
 - 因为再监听器中要创建ApplicationContext对象,需要加载配置文件,上面那个就是监听器默认读取的spring配置文件的路径。默认的名称就是那个嗷!!!  - 你改了就行嘛,改成类路径下文件的名字(这个时候配置文件就是resources里面的spring配置文件的上面了),注意,这一条配置是加在listener标签上面的嗷。 - 实际上记住下面这一坨配置就可以聊,监听器就用上了嗷! - 从全局作用域对象中拿到ServletContext和全局作用域对象等。
 - 上面的web.xml配置文件中的写法: - 1 
 2
 3
 4
 5
 6
 7
 8- <!--监听器注册-->
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:applicationContext.xml</param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>- 代码中获取到这个容器的做法: - 1 
 2
 3
 4
 5
 6
 7- //监听器加入之后的用法
 WebApplicationContext ctx = null;
 String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
 Object attr = getServletContext().getAttribute(key);
 if(attr!=null){
 ctx = (WebApplicationContext)attr;
 }
- 监听器作用: - 将创建的容器对象放入到全局作用域中
 
工具方法获取全局变量:
| 1 |  | 
- summary:- 监听器配置好。
- 代码中可以从全局变量中调出容器即可。
 
- 配置监听器:- 创建容器对象,创建了容器对象之后,就能够把applicationContext中的所有对象都创建好。
- 用户发起请求就可以直接使用对象了。
 
一些小技巧:
- alt+enter可以强制类型转换
- alt+insert可以补充方法
- ctrl+alt+o是为了清楚配置的设置
- 指定路径的时候,默认resources根目录,例如:/ba01/context.xml
- Spring中默认的配置文件名称为applicationContext.xml
- ctrl+F12可以查看类结构
- ctrl+d可以复制一行
- ctrl+y可以删除一行
- ctrl+h可以查看类的继承关系
- 快捷键大全
数据库和Java对象映射
读取的时候:
- 数据库的类型据我发现绝大部分都能够映射为String类型,例如serial啊,数字类型啊等。
- 但是数据库底层如果是char类型的数据 ,就不一定能映射为Java对象中的Integer或者是其他数字类型了。
插入的时候:
- 你设置的类型这个时候就最好和数据库底层符合,不然看起来就会在插值的时候有点怪异orz
- (小声:虽然好像确实可以这么操作,但是这么操作不太好嗷!!!)关于类型转换





