博客
关于我
Spring--04--AOP增强
阅读量:264 次
发布时间:2019-03-01

本文共 9079 字,大约阅读时间需要 30 分钟。

Spring AOP编程增强

切面通知应用增强

在这里插入图片描述

通知类型

  • @Before
  • @AfterReturning
  • @AfterThrowing
  • @After
  • @Around.重点掌握(优先级最高)

说明:在切面类中使用什么通知,由业务决定,并不是说,在切面中要把所有通知都写上。

通知执行顺序

假如这些通知全部写到一个切面对象中,其执行顺序及过程,如图

在这里插入图片描述

代码实践分析如下:

@Component@Aspectpublic class SysTimeAspect {           @Pointcut("bean(sysUserServiceImpl)")        public void doTime(){   }        @Before("doTime()")        public void doBefore(JoinPoint jp){                   System.out.println("time doBefore()");        }        @After("doTime()")        public void doAfter(){                   System.out.println("time doAfter()");        }        /**核心业务正常结束时执行* 说明:假如有after,先执行after,再执行returning*/        @AfterReturning("doTime()")        public void doAfterReturning(){                   System.out.println("time doAfterReturning");        }        /**核心业务出现异常时执行说明:假如有after,先执行after,再执行Throwing*/        @AfterThrowing("doTime()")        public void doAfterThrowing(){                   System.out.println("time doAfterThrowing");        }        @Around("doTime()")       public Object doAround(ProceedingJoinPoint jp)                        throws Throwable{                   System.out.println("doAround.before");         try{                    Object obj=jp.proceed();          System.out.println("doAround.after");          return obj;                 }catch(Throwable e){             System.out.println(e.getMessage());          throw e;         }                     }}

说明:对于@AfterThrowing通知只有在出现异常时才会执行,所以当做一些异常监控时可在此方法中进行代码实现。

切入点表达式增强

Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义及说明:

在这里插入图片描述

bean表达式(重点)

bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:

  • bean(“userServiceImpl”)指定一个userServiceImpl类中所有方法。
  • bean("*ServiceImpl")指定所有后缀为ServiceImpl的类中所有方法。

说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的名字应该是spring容器中某个bean的name。

within表达式(了解)

within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:

  • within(“aop.service.UserServiceImpl”)指定当前包中这个类内部的所有方法。
  • within(“aop.service.*”) 指定当前目录下的所有类的所有方法。
  • within(“aop.service…*”) 指定当前目录以及子目录中类的所有方法。

within表达式应用场景分析:

1)对所有业务bean都要进行功能增强,但是bean名字又没有规则。
2)按业务模块(不同包下的业务)对bean对象进行业务功能增强。

execution表达式(了解)

execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析:

语法:execution(返回值类型 包名.类名.方法名(参数列表))。

  • execution(void aop.service.UserServiceImpl.addUser())匹配addUser方法
  • execution(void aop.service.PersonServiceImpl.addUser(String))方法参数必须为String的addUser方法。
  • execution(* aop.service….(…)) 万能配置。

@annotation表达式(重点)

@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析

  • @annotation(anno.RequiredLog) 匹配有此注解描述的方法。
  • @annotation(anno.RequiredCache) 匹配有此注解描述的方法。

其中:RequiredLog为我们自己定义的注解,当我们使用@RequiredLog注解修饰业务层方法时,系统底层会在执行此方法时进行日扩展操作。

切面优先级设置实现

切面的优先级需要借助@Order注解进行描述,数字越小优先级越高,默认优先级比较低。例如:

在这里插入图片描述
说明:当多个切面作用于同一个目标对象方法时,这些切面会构建成一个切面链,类似过滤器链、拦截器链,其执行分析如图-所示:
在这里插入图片描述

Spring AOP事务处理

Spring 中事务简介

事务定义

事务(Transaction)是一个业务,是一个不可分割的逻辑工作单元,基于事务可以更好的保证业务的正确性。
事务特性
事务具备ACID特性,分别是:

  • 原子性(Atomicity):一个事务中的多个操作要么都成功要么都失败。
  • 一致性(Consistency): 例如存钱操作,存之前和存之后的总钱数应该是一致的。
  • 隔离性(Isolation):事务与事务应该是相互隔离的。
  • 持久性(Durability):事务一旦提交,数据要持久保存。

说明:目前市场上在事务一致性方面,通常会做一定的优化,比方说只要最终一致就可以了,这样的事务我们通常会称之为柔性事务(只要最终一致就可以了).

Spring 中事务管理

Spring框架中提供了一种声明式事务的处理方式,此方式基于AOP代理,可以将具体业务逻辑与事务处理进行解耦。也就是让我们的业务代码逻辑不受污染或少量污染,就可以实现事务控制。

在SpringBoot项目中,其内部提供了事务的自动配置,当我们在项目中添加了指定依赖spring-boot-starter-jdbc时,框架会自动为我们的项目注入事务管理器对象,最常用的为DataSourceTransactionManager对象。

Spring 中事务管理实现

实际项目中最常用的注解方式的事务管理,以注解**@Transactional**配置方式为例,进行实践分析。

基于@Transactional 注解进行声明式事务管理的实现步骤分为两步:

  1. 启用声明式事务管理,在项目启动类上添加@EnableTransactionManagement,新版本中也可不添加(例如新版SpringBoot项目)
  2. 将@Transactional注解添加到合适的业务类或方法上,并设置合适的属性信息。 其代码示例如下:
@Transactional(timeout = 30,               readOnly = false,               isolation = Isolation.READ_COMMITTED,               rollbackFor = Throwable.class,               propagation = Propagation.REQUIRED)  @Service  public class implements SysUserService {       @Transactional(readOnly = true)    @Override         public PageObject
findPageObjects(String username, Integer pageCurrent) { … }}

其中,代码中的@Transactional注解用于描述类或方法,告诉spring框架我们要在此类的方法执行时进行事务控制,其具体说明如下:。

  • 当@Transactional注解应用在类上时表示类中所有方法启动事务管理,并且一般用于事务共性的定义。
  • 当@Transactional描述方法时表示此方法要进行事务管理,假如类和方法上都有

@Transactional注解,则方法上的事务特性优先级比较高。

@Transactional 常用属性应用说明:

  • timeout:事务的超时时间,默认值为-1,表示没有超时显示。如果配置了具体时间,则超过该时间限制但事务还没有完成,则自动回滚事务。这个时间的记录方式是在事务开启以后到sql语句执行之前。
  • read-only:指定事务是否为只读事务,默认值为false;为了忽略那些不需要事务的方法,比如读取数据,可以设置read-only为true。对添加,修改,删除业务read-only的值应该为false。
  • rollback-for:用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
  • no-rollback- for: 抛出no-rollback-for 指定的异常类型,不回滚事务。
  • isolation事务的隔离级别,默认值采用 DEFAULT。当多个事务并发执行时,可能会出现脏读,不可重复读,幻读等现象时,但假如不希望出现这些现象可考虑修改事务的隔离级别(但隔离级别越高并发就会越小,性能就会越差)

Spring 中事务控制过程分析,如图-所示:

在这里插入图片描述

Spring事务管理是基于接口代理(JDK)或动态字节码(CGLIB)技术,然后通过AOP实施事务增强的。当我们执行添加了事务特性的目标方式时,系统会通过目标对象的代理对象调用DataSourceTransactionManager对象,在事务开始的时,执行doBegin方法,事务结束时执行doCommit或doRollback方法。

Spring 中事务传播特性

事务传播(Propagation)特性指"不同业务(service)对象"中的事务方法之间相互调用时,事务的传播方式,如图-所示

在这里插入图片描述
其中,常用事务传播方式如下:

  • @Transactional(propagation=Propagation.REQUIRED)

如果没有事务创建新事务, 如果当前有事务参与当前事务, Spring 默认的事务传播行为是PROPAGATION_REQUIRED,它适合于绝大多数的情况。假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:

Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。如图-所示:

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

  • @Transactional(propagation=Propagation.REQUIRES_NEW)
    必须是新事务, 如果有当前事务, 挂起当前事务并且开启新事务,如图-所示:
    在这里插入图片描述
    在这里插入图片描述
    当有一个业务对象调用如上业务方法时,此方法会始终运行在一个新的事务中。

Spring 中事务管理小结

Spring 声明式事务是 Spring 最核心,最常用的功能。由于 Spring 通过 IOC 和 AOP的功能非常透明地实现了声明式事务的功能,对于一般的开发者基本上无须了解 Spring声明式事务的内部细节,仅需要懂得如何配置就可以了。但对于中高端开发者还需要了解其内部机制。

Spring AOP 异步操作实现

异步场景分析

在开发系统的过程中,通常会考虑到系统的性能问题,提升系统性能的一个重要思想就是“串行”改“并行”。说起“并行”自然离不开“异步”,今天我们就来聊聊如何使用Spring的**@Async**的异步注解。

Spring 业务的异步实现

  1. 启动异步配置
    在基于注解方式的配置中,借助@EnableAsync注解进行异步启动声明,Spring Boot版的项目中,将@EnableAsync注解应用到启动类上,代码示例如下
@EnableAsync //spring容器启动时会创建线程   @SpringBootApplication   public class Application {           public static void main(String[] args) {                  SpringApplication.run(Application.class, args);        }}

2.Spring中@Async注解应用

在需要异步执行的业务方法上,使用**@Async**方法进行异步声明。
在这里插入图片描述
其中,AsyncResult对象可以对异步方法的执行结果进行封装,假如外界需要异步方法结果时,可以通过Future对象的get方法获取结果。

spring框架下的连接池

当我们需要自己对spring框架提供的连接池进行一些简易配置,可以参考如下代码

spring:  task:    execution:      pool:        queue-capacity: 128        core-size: 5        max-size: 128        keep-alive: 60000      thread-name-prefix: db-service-task-

对于spring框架中线程池配置参数的涵义,可以参考ThreadPoolExecutor对象中的解释。

说明:对于@Async注解默认会基于ThreadPoolTaskExecutor对象获取工作线程,然后调用由@Async描述的方法,让方法运行于一个工作线程,以实现异步操作。但是假如系统中的默认拒绝处理策略,任务执行过程的异常处理不能满足我们自身业务需求的话,我可以对异步线程池进行自定义.(SpringBoot中默认的异步配置可以参考自动配置对象TaskExecutionAutoConfiguration).

Spring 自定义异步池的实现

为了让Spring中的异步池更好的服务于我们的业务,同时也尽量避免OOM,可以自定义线程池优化设计如下:关键代码如下:

package com.cy.pj.common.config@Slf4j@Setter@Configuration@ConfigurationProperties("async-thread-pool")public class SpringAsyncConfig implements AsyncConfigurer{       /**核心线程数*/        private int corePoolSize=20;        /**最大线程数*/        private int maximumPoolSize=1000;        /**线程空闲时间*/        private int keepAliveTime=30;        /**阻塞队列容量*/        private int queueCapacity=200;        /**构建线程工厂*/        private ThreadFactory threadFactory=new ThreadFactory() {                   //CAS算法                private AtomicInteger at=new AtomicInteger(1000);                @Override                public Thread newThread(Runnable r) {                           return new Thread(r,"db-async-thread-"+at.getAndIncrement());                }        };                @Override    public Executor getAsyncExecutor() {           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();        executor.setCorePoolSize(corePoolSize);        executor.setMaxPoolSize(maximumPoolSize);        executor.setKeepAliveSeconds(keepAliveTime);        executor.setQueueCapacity(queueCapacity);        executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) -> {                   log.warn("当前任务线程池队列已满.");        });        executor.initialize();        return executor    }    @Override    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {         return new AsyncUncaughtExceptionHandler() {                           @Override            public void handleUncaughtException(Throwable ex ,Method method , Object... params) {                  log.error("线程池执行任务发生未知异常.", ex);            }        };    }}

其中:@ConfigurationProperties(“async-thread-pool”)的含义是读取application.yml配置文件中以"async-thread-pool"名为前缀的配置信息,并通过所描述类的set方法赋值给对应的属性,在application.yml中连接器池的关键配置如下:

async-thread-pool:       corePoolSize: 20       maxPoolSize: 1000       keepAliveSeconds: 30       queueCapacity: 1000

后续在业务类中,假如我们使用@Async注解描述业务方法,默认会使用ThreadPoolTaskExecutor池对象中的线程执行异步任务。

Spring AOP中Cache操作实现

缓存场景分析

在业务方法中我们可能调用数据层方法获取数据库中数据,假如访问数据的频率比较高,为了提高的查询效率,降低数据库的访问压力,可以在业务层对数据进行缓存.

Spring 中业务缓存应用实现

1.启动缓存配置

在项目(SpringBoot项目)的启动类上添加@EnableCaching注解,以启动缓存配置。关键代码如下:

在这里插入图片描述

2.业务方法上应用缓存配置

业务方法上应用缓存配置

在需要进行缓存的业务方法上通过@Cacheable注解对方法进行相关描述.表示方法的返回值要存储到Cache中,假如在更新操作时需要将cache中的数据移除,可以在更新方法上使用@CacheEvict注解对方法进行描述。例如:

第一步:在相关模块查询相关业务方法中,使用缓存,关键代码如下:

在这里插入图片描述
其中,value属性的值表示要使用的缓存对象,名字自己指定,其中底层为一个map对象,当向cache中添加数据时,key默认为方法实际参数的组合。

第二步:在相关模块更新时,清除指定缓存数据,关键代码如下:

在这里插入图片描述
其中,allEntries表示清除所有。

spring中的缓存应用原理

在这里插入图片描述

Spring中自定义缓存的实现

在Spring中默认cache底层实现是一个Map对象,假如此map对象不能满足我们实际需要,在实际项目中我们可以将数据存储到第三方缓存系统中.

转载地址:http://ljmo.baihongyu.com/

你可能感兴趣的文章
《Spring Boot 2.0 极简教程》附录 I : Spring 5.0 新特性
查看>>
IDEA 工程文件 UTF-8 编码设置
查看>>
10年后6G将问世,速度有望比5G快100倍
查看>>
5G蝴蝶效应:孕育万亿级产业
查看>>
华为超越三星拿下第一!2019年全球5G手机出货量榜单揭晓
查看>>
中国电信为武汉协和搭建的5G远程会诊平台正式投入使用!
查看>>
PPT分享 | 中国移动十大领域5G应用案例
查看>>
宝信软件丛力群:工业互联网赋能钢铁行业高质量发展
查看>>
550亿元,15万个5G基站!重庆5G专项规划来了
查看>>
芯片巨头AMD获得许可:供货华为
查看>>
7个国家级、省级车联网先导区详细介绍!
查看>>
小米等9家中企又被美“拉黑”;工信部公布81项通信行业标准;诺基亚获5G合同...
查看>>
79家信息技术企业,募资1600亿!科创板企业募资、市值、涨幅情况排行榜发布...
查看>>
官宣:湘江智能“车-站-路-云”一体化协同智慧公交解决方案来啦!
查看>>
【论文写作PS】两张图片合为一张,不覆盖
查看>>
【程序】打包opencv程序
查看>>
浅谈算法——从多项式乘法到FFT
查看>>
bug宝典JAVA篇 maven打不进xml文件
查看>>
第3.1.6章 WEB系统最佳实践 js控件之bootstrap table
查看>>
C++基础(一)数据类型
查看>>