文章内容输出来源:拉勾教育Java高薪训练营
前言:
由于工作需要提升自身技术能力,在各方比较下,报名了拉勾教育的java高薪训练营,目前已经学了半个月啦,来说说自身学习的感受吧:
- 课程内容有广度更有深度,几乎目前进大厂需要的主流技术点都覆盖了,包括比较新的mybatis-plus,k8s,flink等等,深度方面,更是带领大家一起分析并手写框架,然后去翻阅源代码学习原理,这样学习效果会更好;
- 老师讲课也是很有水平,通过画图各种方式来讲解课程内容,并且课程有基础回顾,有高级的技术点,也有一些面试高频题的讲解;
- 每个阶段的学习都有作业,需要认真学习并对待才能完成作业,作业挺有难度,包括简答题和编程题,有些还需要自己画图来完成;
- 学习过程中,会有班主任的督促学习,并且答疑老师也是非常耐心,经常晚上都还在帮同学解答问题;
- 课程内容挺多,需要花时间来认真学习,只要自己努力了,肯定不会亏,加油冲大厂。
一、Spring概述
1、Spring简介
Spring
是一个分层的全栈轻量级开源框架,核心是IOC
和AOP
,还能整合众多的第三方开源框架和类库,已经成为使用最多的JAVA EE
企业级应用开源框架。
2、Spring优势
- 方便解耦,简化开发
AOP
编程的支持- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低
JavaEE API
的使用难度 - 源码是经典的
JAVA
学习范例
3、Spring的核心结构
Spring
是一个层级清晰,职责分明、且依赖关系非常轻量的框架,主要包括几个模块:
- 数据处理模块
Spring
的JDBC
和DAO
模块封装了大量样板代码,使得数据库代码更加简洁,开发者可以更加专注业务,还可以避免数据库资源释放失败而引起的问题。另外,Spring AOP
为数据访问提供了事务管理服务,同时还集成了其他ORM
框架
- WEB模块
该模块提供了SpringMVC
框架给WEB应用,还提供了多种构建和其他应用交互的远程调用方案,SpringMVC
框架在WEB层提升了应用的松耦合水平。
- 面向切面编程
AOP
模块:
对面向切面编程提供了丰富的支持。这个模块是Spring应用系统中开发切面的基础,与DI
一样,AOP
可以帮助应用对象解耦。
Spring
核心容器Core Container
模块:
是Spring
框架最核心的部分,它管理着Spring
应用中bean
的创建、配置和管理。在该模块中,包括了Spring Bean
工厂,为Spring提供了DI
功能。基于Bean
工厂,我们还会发现多种Spring
应用上下文的实现,所有的Spring
模块都构建于核心容器之上
- TEST模块
为了使开发者能够很方便进行测试,Spring
提供了测试模块来进行Spring
应用的测试。
如下图所示:
二、Spring核心
IOC
和AOP
是Spring
的核心
1、IOC
1.1、IOC的定义
IOC
,控制反转,它是一个技术思想,核心就是将new
对象的操作交由IOC
容器去帮助我们完成,包括创建实例化对象并管理它,我们需要使用哪个对象,去IOC
容器获取即可。控制指的是对象创建(实例化、管理)的权力,反转指的是控制权交给了外部环境(IOC
容器)
1.2、IOC解决了什么问题
- 对象之间的耦合问题
1.3、IOC和DI的区别
IOC
和DI
描述的是同一件事情(对象实例化以及依赖关系维护这件事),只是不同角度罢了。
IOC
是站在对象的角度,对象实例化及其管理的权力交给了容器,DI
是站在容器的角度,容器会把对象依赖的属性注入。
2、AOP
2.1、AOP定义
面向切面编程,是OOP
(面向对象)的延续,OOP
解决不了以下问题:
- 代码重复问题
- 逻辑代码和业务代码混杂在一起,代码臃肿,维护不方便
AOP
提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离
2.2、AOP解决了什么问题
在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。
2.3、为什么叫做面向切面编程
切:指的是横切逻辑,原有业务逻辑代码我们不能动,只能操作横切逻辑代码,所以⾯向横切逻辑
⾯:横切逻辑代码往往要影响的是很多个⽅法,每⼀个⽅法都如同⼀个点,多个点构成⾯,有⼀个 ⾯的概念在⾥⾯
三、Spring IOC应用
1、Spring IOC基础
beans.xml
:定义需要实例化对象的类的全限定名以及其各个类之间的依赖关系描述BeanFactory
:IOC
容器,通过反射技术来实例化对象并维护对象之间的依赖关系
2、Spring IOC的三种实现方式
- 纯XML(BEAN信息完全定义在XML中)
- XML+注解(部分bean使用XML定义,部分bean使用注解定义)
- 纯注解模式(所有的bean都是通过注解来定义)
3、BeanFactory和ApplicationContext的区别
BeanFactory
是Spring
框架IOC
容器的顶层接口,用于定义一些基础功能和规范,ApplicationContext
是它的一个子接口。通常我们称BeanFactory
是Spring IOC
的基础容器,ApplicationContext
是容器的高级接口,比BeanFactory
拥有更多功能,比如说国际化支持和资源访问(XML
、JAVA
配置类等)。
4、实例化Bean的三种方式
- 使用无参构造函数
在默认情况下,通过反射调用无参构造函数来创建对象,如果类中没有无参构造函数,则创建对象失败。
<bean id="ConnUtils" class="com.lagou.edu.utils.ConnUtils"> </bean>
- 使用静态方法创建
<bean id="userService" class="com.lagou.factory.BeanFactory" factory-method="getTransferService"></bean>
- 使用实例化方法创建
<bean id="beanFactory"
class="com.lagou.factory.instancemethod.BeanFactory"></bean>
<bean id="transferService" factory-bean="beanFactory" factorymethod="getTransferService"></bean>
5、Bean的作用范围及生命周期
作用范围:
singleton
:单例模式,在容器中仅有一个实例对象,IOC
创建的对象默认都是单例的prototype
:原型模型(多例模式),每次getBean
都会创建一个新的对象request
:(web环境)每个request
请求维护一个实例session
(web环境)每个session
会话维护一个实例application
(web环境)每个应用上下文维护一个实例websocket
(web环境)
实际开发中常用的就singleton
和prototype
这两种模式。配置如下
<bean id="transferService"
class="com.lagou.service.impl.TransferServiceImpl" scope="singleton">
</bean>
不同作用范围有不同的生命周期:
- 单例模式:单例模式bean对象生命周期与容器相同
- 多例模式:每次使用对象都重新创建一个新对象,
Spring
框架只负责创建,销毁由JAVA
垃圾回收器负责
6、bean标签的常用属性
id
属性:bean
对象的唯一标识class
属性:类全限定名name
属性:类名称,可以重复,没啥用factory-bean
属性:用于指定创建当前bean
对象的⼯⼚⽅法,如配合factory-bean
属性使⽤, 则class
属性失效。如配合class
属性使⽤,则⽅法必须是static
的。scope
:指定bean
对象的作用范围,默认是singleton
init-method
属性:指定bean
对象的初始化方法,此方法会在bean
对象装配后调用,该方法必须是一个无参方法destory-method
属性:⽤于指定bean对象的销毁⽅法,此⽅法会在bean
对象销毁前执⾏。它只 能为scope
是singleton
时起作⽤。
7、常用注解
@Autowired
:根据指定的类型注入@Qualifier
:告诉Spring
具体去装配哪个对象,可以结合@Autowired
唯一确定对象@Resource
: 默认按照ByName
自动注入@Configuration
:表名当前类是一个配置类@ComponentScan
: 注解,替代context:component-scan
@PropertySource
:引⼊外部属性配置⽂件@Import
:引⼊其他配置类@Value
:对变量赋值,可以直接赋值,也可以使⽤${}
读取资源配置⽂件中的信息@Bean
:将⽅法返回对象加⼊Spring IOC
容器
Spring IOC高级特性
1、lazy-init延迟加载
延迟加载指的是Spring Bean
的延迟创建。
默认情况下,Spring
会在容器启动时就将所有的singleton bean
提前进行实例化,例如:
<bean id="ConnUtils" class="com.lagou.edu.utils.ConnUtils" lazy-init="false"></bean>
lazy-init
为false
表示在spring
启动时,立即进行实例化该bean
如果不想让某个singleton bean
在ApplicationContext
初始化时被提前实例化,可以将bean
设置为延迟加载,即将lazy-init
属性设为true
即可,此时的bean
只有当第一次向容器getBean
的时候才会进行实例化。
如果一个设置了立即加载的bean1
,引用了一个延迟加载的bean2
,那么bean1
在容器启动时被实例化,而bean2
由于被bean1
引用,也在此时被实例化,符合延迟加载的bean
在第一次被使用时才初始化的原则。
如果一个bean
的scope
属性为scope="prototype"
时,即使设置了lazy-init=false
,容器启动时也不会实例化bean
,而是调用getBean
方法才会进行初始化。
延迟加载应用场景:
- 开启延迟加载一定程度提高容器启动和运转性能
- 对于不常使⽤的 Bean 设置延迟加载,这样偶尔使⽤的时候再加载,不必要从⼀开始该
Bean
就占 ⽤资源
容器不是一个Map
,map
其实只是ioc
容器的一个成员,叫单例池,容器是一组组件和过程的集合,包括BeanFactory
、单例池、BeanPost
。
四、Spring AOP应用
AOP
本质:在不改变原有业务逻辑的情况下增强横切逻辑,常用于权限校验、日志记录、事务控制、性能监控等。
1、Spring AOP术语
Joinpoint
(连接点):可以将增强代码加入到业务中的方法点PointCut
(切入点):具体实现增强的业务方法点Advice
(通知、增强):值切面类中用于提供增强功能的方法,并且不同方法增强的时机是不一样的,分类有:前置通知、后置通知、异常通知、最终通知、环绕通知- `Target`(目标对象):代理的目标对象,即被代理对象
Proxy
(代理):指一个类被AOP
织入增强后,产生的代理对象Weaving
(织入):指把增强应用到目标对象来创建新的代理对象的过程,Spring
采用动态代理来实现Aspect
(切面):指增强的代码所关注的方面,把这些相关的增强代码定义到一个类中,这个类就是切面类
切面=切入点(锁定方法)+方位点(锁定方法中的特殊时机)+横切逻辑
2、Spring中AOP的代理选择
Spring AOP
思想是通过动态代理技术来实现的。
在默认情况下,Spring
会根据被代理对象是否实现接口来选择JDK
还是CGLIB
代理,如果被代理类未实现接口,则采用CGLIB
代理,如果实现了接口,则采用JDK
动态代理,我们也可以通过配置来让Spring
强制使用CGLIB
代理。
3、Spring中AOP的配置方式
Spring
中AOP
也有三种配置方式:
XML
XML
+注解组合- 纯注解
4、Spring中AOP实现
XML模式
- 导入jar包:
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.1.12.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency>
- AOP核心配置:
<!--把通知bean交给spring来管理-->
<bean id="logUtil" class="com.lagou.utils.LogUtil"></bean>
<!--开始aop的配置-->
<aop:config>
<!--配置切⾯--><aop:aspect id="logAdvice" ref="logUtil"><!--配置前置通知--><aop:before method="printLog" pointcut="execution(public *
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou
.pojo.Account))"></aop:before></aop:aspect>
</aop:config>
- 切入点表达式
pointcut
的表达式规则:
访问修饰符 返回值 包名.包名.包名.类名.方法名(参数列表)
其中访问修饰符可以省略
返回值可以使用*表示任意返回值
包名可以使用.表示任意包,但是有几级包就对应几个. , 因此可以使用..来表示当前包及其子包
类和方法名都可以使用.表示任意类、任意方法
参数列表,基本类型直接写类型名称,如int
,引用类型必须写全限定类名,如java.lang.String
参数列表可以使用..表示有无参数均可
全通配方式:* *..*.*(..)
- 修改代理方式配置:
- 方式一:使⽤
aop:config
标签配置
- 方式一:使⽤
<aop:config proxy-target-class="true">
- 方式二:使⽤aop:aspectj-autoproxy标签配置
<!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP的⽀持--><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectjautoproy>
- 五种通知类型:
- 前置通知:
aop:before
标签:
- 前置通知:
<!--作⽤:⽤于配置前置通知。出现位置:它只能出现在aop:aspect标签内部属性:method:⽤于指定前置通知的⽅法名称pointcut:⽤于指定切⼊点表达式pointcut-ref:⽤于指定切⼊点表达式的引⽤--><aop:before method="printLog" pointcut-ref="pointcut1"></aop:before>
- 正常执行的通知:after-returning标签
<!--作⽤:⽤于配置正常执⾏时通知出现位置:它只能出现在aop:aspect标签内部属性:method:⽤于指定后置通知的⽅法名称pointcut:⽤于指定切⼊点表达式pointcut-ref:⽤于指定切⼊点表达式的引⽤--><aop:after-returning method="afterReturningPrintLog" pointcutref="pt1"></aop:after-returning>
- 异常通知:after-throwing标签
<!--作⽤:⽤于配置异常通知。出现位置:它只能出现在aop:aspect标签内部属性:method:⽤于指定异常通知的⽅法名称pointcut:⽤于指定切⼊点表达式pointcut-ref:⽤于指定切⼊点表达式的引⽤--><aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>
- 最终通知:after标签
<!--作⽤:⽤于指定最终通知。出现位置:它只能出现在aop:aspect标签内部属性:method:⽤于指定最终通知的⽅法名称pointcut:⽤于指定切⼊点表达式pointcut-ref:⽤于指定切⼊点表达式的引⽤--><aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
无论切入点方法是否产生异常,都会在返回之前执行- 环绕通知:around标签
<!--作⽤:⽤于配置环绕通知。出现位置:它只能出现在aop:aspect标签的内部属性:method:⽤于指定环绕通知的⽅法名称pointcut:⽤于指定切⼊点表达式pointcut-ref:⽤于指定切⼊点表达式的引⽤--><aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>
环绕通知有别于其他通知,一般不与其他通知一起配置使用,它是Spring框架为我们提供的一种可以通过编码方式,控制增强代码何时执行的通知类型。
XML+注解模式
XML
中开启Spring
对注解AOP
的支持
<!--开启spring对注解aop的⽀持--><aop:aspectj-autoproxy/>
#### 注解模式
配置类加入如下注解:
@Configuration@ComponentScan("com.lagou")@EnableAspectJAutoProxy //开启spring对注解AOP的⽀持public class SpringConfiguration {}
5、Spring声明式事务支持
1、事务基础
1.1 事务概念
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败,从而确保数据的准确与安全
1.2 事务的四大特性
- 原子性:事务是一个不可分割的工作单元,事务中的操作要么全部发生,要么都不发生
- 一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态
- 隔离性:多个用户并行访问数据库时,数据库为每一个用户开启的事务,每个事务不能被其他事务的操作数据所干扰,多个并发事务之间要隔离
- 持久性:一个事务一旦提交,它对数据库中数据的改变就是持久性的,即使数据库发生故障也不应该对其有影响
1.3 事务的隔离级别
如果不考虑隔离级别,会出现以下情况:
- 脏读:一个线程中的事务读到了另一个线程中未提交的数据
- 不可重复读:一个线程中的事务读到了另一个线程中已经提交的update数据(前后内容不一致)
- 虚读(幻读):一个线程中的事务读到了另一个线程中已经提交的Insert或者update的数据(前后条数不一致)
数据库的隔离级别:
Serializable
(串行化):可避免脏读、不可重复读、虚读情况发生。(每个线程都排队进行访问)级别最高Repeatable read
(可重复读):可避免脏读、不可重复读的情况发生(幻读有可能发生)。该机制下会对要update的行进行加锁 级别第二Read committed
(读已提交):可避免脏读情况发生 级别第三Read uncommitted
(读未提交):最低级别,以上情况均⽆法保证。(读未提交) 级别最低
效率与级别高低成反比
MYSQL
默认的隔离级别是:REPEATABLE READ
查询当前使⽤的隔离级别: select @@tx_isolation;
设置MySQL
事务的隔离级别: set session transaction isolation level xxx;
(设置的是当前 mysql
连接会话的,并不是永久改变的)
1.4 事务的传播行为
事务往往在service
层进行控制,如果出现service层方法A调用了另一个service
层方法B,A和B方法本身都已经添加了事务控制,那么A在调用B的时候,就需要进行一些事务策略的协商,这就叫做事务的传播行为。
PROPAGATION_REQUIRED
:如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中, 加⼊到这个事务中。这是最常⻅的选择。PROPAGATION_SUPPORTS
:⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。
2、Spring声明式事务配置
2.1 纯XML模式
- 导入jar包:
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.12.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.12.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.1.12.RELEASE</version></dependency>
- XML配置
<tx:advice id="txAdvice" transaction-manager="transactionManager"><!--定制事务细节,传播⾏为、隔离级别等--><tx:attributes><!--⼀般性配置--><tx:method name="*" read-only="false"propagation="REQUIRED" isolation="DEFAULT" timeout="-1"/><!--针对查询的覆盖性配置--><tx:method name="query*" read-only="true"propagation="SUPPORTS"/></tx:attributes></tx:advice><aop:config><!--advice-ref指向增强=横切逻辑+⽅位--><aop:advisor advice-ref="txAdvice" pointcut="execution(*com.lagou.edu.service.impl.TransferServiceImpl.*(..))"/></aop:config>
2.2 XML+注解
- XML配置
<!--配置事务管理器--><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--开启spring对注解事务的⽀持--><tx:annotation-driven transaction-manager="transactionManager"/>
- 在接⼝、类或者⽅法上添加@Transactional注解
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
2.3 纯注解
Spring
基于注解驱动开发的事务控制配置,只需要把 xml
配置部分改为注解实现。只是需要⼀个 注解替换掉xml
配置⽂件中的 配置。 在 Spring
的配置类上添加 @EnableTransactionManagement
注解即可。配置如下:
@EnableTransactionManagement//开启spring注解事务的⽀持public class SpringConfiguration {}