spring aop实例讲解_Spring框架核心知识点

5429d7a6646ff2cca2bcce7e5917589e.png

文章内容输出来源:拉勾教育Java高薪训练营

前言:

由于工作需要提升自身技术能力,在各方比较下,报名了拉勾教育的java高薪训练营,目前已经学了半个月啦,来说说自身学习的感受吧:

  • 课程内容有广度更有深度,几乎目前进大厂需要的主流技术点都覆盖了,包括比较新的mybatis-plus,k8s,flink等等,深度方面,更是带领大家一起分析并手写框架,然后去翻阅源代码学习原理,这样学习效果会更好;
  • 老师讲课也是很有水平,通过画图各种方式来讲解课程内容,并且课程有基础回顾,有高级的技术点,也有一些面试高频题的讲解;
  • 每个阶段的学习都有作业,需要认真学习并对待才能完成作业,作业挺有难度,包括简答题和编程题,有些还需要自己画图来完成;
  • 学习过程中,会有班主任的督促学习,并且答疑老师也是非常耐心,经常晚上都还在帮同学解答问题;
  • 课程内容挺多,需要花时间来认真学习,只要自己努力了,肯定不会亏,加油冲大厂。

一、Spring概述

1、Spring简介

Spring是一个分层的全栈轻量级开源框架,核心是IOCAOP,还能整合众多的第三方开源框架和类库,已经成为使用最多的JAVA EE企业级应用开源框架。

2、Spring优势

  • 方便解耦,简化开发
  • AOP编程的支持
  • 声明式事务的支持
  • 方便程序的测试
  • 方便集成各种优秀框架
  • 降低JavaEE API的使用难度
  • 源码是经典的JAVA学习范例

3、Spring的核心结构

Spring是一个层级清晰,职责分明、且依赖关系非常轻量的框架,主要包括几个模块:

  • 数据处理模块

SpringJDBCDAO模块封装了大量样板代码,使得数据库代码更加简洁,开发者可以更加专注业务,还可以避免数据库资源释放失败而引起的问题。另外,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应用的测试。

如下图所示:

3816e0a92b6da2e5d8c6ec906ceb88c1.png

二、Spring核心

IOCAOPSpring的核心

1、IOC

1.1、IOC的定义

IOC,控制反转,它是一个技术思想,核心就是将new对象的操作交由IOC容器去帮助我们完成,包括创建实例化对象并管理它,我们需要使用哪个对象,去IOC容器获取即可。控制指的是对象创建(实例化、管理)的权力,反转指的是控制权交给了外部环境(IOC容器)

1.2、IOC解决了什么问题

  • 对象之间的耦合问题

1.3、IOC和DI的区别

IOCDI描述的是同一件事情(对象实例化以及依赖关系维护这件事),只是不同角度罢了。

IOC是站在对象的角度,对象实例化及其管理的权力交给了容器,DI是站在容器的角度,容器会把对象依赖的属性注入。

2、AOP

2.1、AOP定义

面向切面编程,是OOP(面向对象)的延续,OOP解决不了以下问题:

  • 代码重复问题
  • 逻辑代码和业务代码混杂在一起,代码臃肿,维护不方便

AOP提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离

2.2、AOP解决了什么问题

在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。

2.3、为什么叫做面向切面编程

切:指的是横切逻辑,原有业务逻辑代码我们不能动,只能操作横切逻辑代码,所以⾯向横切逻辑

⾯:横切逻辑代码往往要影响的是很多个⽅法,每⼀个⽅法都如同⼀个点,多个点构成⾯,有⼀个 ⾯的概念在⾥⾯

三、Spring IOC应用

1、Spring IOC基础

  • beans.xml:定义需要实例化对象的类的全限定名以及其各个类之间的依赖关系描述
  • BeanFactoryIOC容器,通过反射技术来实例化对象并维护对象之间的依赖关系

2、Spring IOC的三种实现方式

  • 纯XML(BEAN信息完全定义在XML中)
  • XML+注解(部分bean使用XML定义,部分bean使用注解定义)
  • 纯注解模式(所有的bean都是通过注解来定义)

3、BeanFactory和ApplicationContext的区别

BeanFactorySpring框架IOC容器的顶层接口,用于定义一些基础功能和规范,ApplicationContext是它的一个子接口。通常我们称BeanFactorySpring IOC的基础容器,ApplicationContext是容器的高级接口,比BeanFactory拥有更多功能,比如说国际化支持和资源访问(XMLJAVA配置类等)。

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环境)

实际开发中常用的就singletonprototype这两种模式。配置如下

<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对象销毁前执⾏。它只 能为scopesingleton时起作⽤。

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-initfalse表示在spring启动时,立即进行实例化该bean

如果不想让某个singleton beanApplicationContext初始化时被提前实例化,可以将bean设置为延迟加载,即将lazy-init属性设为true即可,此时的bean只有当第一次向容器getBean的时候才会进行实例化。

如果一个设置了立即加载的bean1,引用了一个延迟加载的bean2,那么bean1在容器启动时被实例化,而bean2由于被bean1引用,也在此时被实例化,符合延迟加载的bean在第一次被使用时才初始化的原则。

如果一个beanscope属性为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的配置方式

SpringAOP也有三种配置方式:

  • 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.DataSourceTransactionManage
    r">
     <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 {
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值