1. AOP 概述

1.1 AOP 是什么?

AOP(Aspect Orient Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善。它以通过预编译方式和运行期动态代理方式,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。

AOP与OOP字面意思相近,但其实两者完全是面向不同领域的设计思想。实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面的运行期代理方式,理解为一个动态过程,可以在对象运行时动态织入一些扩展功能或控制对象执行。

AOP就是要基于OCP(开闭原则),在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以"控制"对象的执行。例如AOP应用于项目中的日志处理,事务处理,权限处理,缓存处理等等。
image.png

![image.png](/img/bVbOW0a)

明:Spring boot2.x 中AOP现在默认使用的CGLIB代理,假如需要使用JDK动态代理可以在配置文件(applicatiion.properties)中进行如下配置:

spring.aop.proxy-target-class=false

image.png

2. Spring AOP快速实践

2.1 项目创建及配置

创建maven项目或在已有项目基础上添加AOP启动依赖:

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-aop</artifactId>

</dependency>

2.2 扩展业务分析及实现

package com.cy.pj.common.aspect;

@Aspect

@Slf4j

@Component

public class SysLogAspect {

 @Pointcut("bean(sysUserServiceImpl)")

 public void logPointCut() {}

 @Around("logPointCut()")

 public Object around(ProceedingJoinPoint jp)

 throws Throwable{

 try {

 log.info("start:{}"+System.currentTimeMillis());

 Object result=jp.proceed();//最终会调用目标方法

 log.info("after:{}"+System.currentTimeMillis());

 return result;

 }catch(Throwable e) {

 log.error("after:{}",e.getMessage());

 throw e;

 }

 }

}

说明:

  • @Aspect 注解用于标识或者描述AOP中的切面类型,基于切面类型构建的对象用于为目标对象进行功能扩展或控制目标对象的执行。
  • @Pointcut注解用于描述切面中的方法,并定义切面中的切入点(基于特定表达式的方式进行描述),在本案例中切入点表达式用的是bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的名字。
  • @Around注解用于描述切面中方法,这样的方法会被认为是一个环绕通知(核心业务方法执行之前和之后要执行的一个动作),@Aournd注解内部value属性的值为一个切入点表达式或者是切入点表达式的一个引用(这个引用为一个@PointCut注解描述的方法的方法名)。
  • ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的目标方法相关的一些信息。只能用于@Around注解描述的方法参数。

image.png

image.png

image.png

3. Spring AOP编程增强

在基于Spring AOP编程的过程中,基于AspectJ框架标准,spring中定义了五种类型的通知(通知描述的是一种扩展业务),它们分别是:

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

    image.png

总结:

1.AOP是一种设计思想(面向切片编程),实现在不修改源代码的情况下给程序

动态统一添加额外功能的一种技术;

2.AOP和OOP区别:但其实两者完全是面向不同领域的设计思想。实际项目中我们

通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面的运行期代理方式,理解为一个动态过程,可以在对象运行时动态织入一些扩展功能或控制对象执行。

AOP的应用场景:AOP就是要基于OCP(开闭原则),在不改变原有系统核心业务代

码的基础上动态添加一些扩展功能并可以"控制"对象的执行。例如AOP应用于项目中的日志处理,事务处理,权限处理,缓存处理等等。

AOP的使用步骤:首先添加jar文件;

1.类上添加注解:@Aspect,@Commpent,@Slf4j(需要日志的时候添加)
2.在类中添加切入点:两种方式:@Pointcut("bean(sysLogServiceImpl)"),
@Pointcut("@annotation(类全名)")
3.@annotation作为注解切入点方式的步骤:
(1).在另外一个类上面添加一个注解
image.png
(2).在切面类上使用切面和Around方式添加缓存:
image.png
(3)使用注解在特指的方法上面:
image.png

4.添加一个载体方法;
5.通过“五种通知”:@Around,@Before,@After,@After,@AfterReturning,@AfterThrowing,执行顺序是:
image.png
6.Around环绕通知使用注意:
image.png

3. 切面优先级设置实现

image.png

image.png

4. Spring AOP事务处理

image.png

4.12. Spring 中事务管理实现

步骤:

1.添加注解::@Transactional
2.注解:@Transactional (参数):
<1>Timeout:默认是:-1,表示事务执行时的超时时间:-1表示没有超时时间;
<2>read-only:(表示只读类型):默认是false(读取全部),设置为true的话,是指只能进行查询业务;
<3>.rollback-for:用于指定回滚的触发异常类型,如果有多个异常类型的话,可以加逗号分隔;
<4>.no-rollback-for:抛出no-rollback-for指定的异常类型,不进行回滚;
<5>.isolation:务的隔离级别,默认值采用 DEFAULT。当多个事务并发执行时,可能会出现脏读,不可重复读,幻读等现象时,但假如不希望出现这些现象可考虑修改事务的隔离级别(但隔离级别越高并发就会越小,性能就会越差)

注意:

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

image.png

2.3. spring 中事务传播特性

如果有嵌套事务时:应该将注解放在事务中:
image.png

传播方式:
1.

image.png

2.

image.png

5. Spring AOP 异步操作实现

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

5.1 实现步骤:

1.添加注解:@EnableAsync 放在启动类上面,容器创建线程池;

image.png

2.把注解@Async放在方法上面进行异步声明:

image.png

需要返回业务层方法的执行结果的话,如下:
image.png

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

 task:

 execution:

 pool:

 queue-capacity: 128

 core-size: 5

 max-size: 128

 keep-alive: 60000

 thread-name-prefix: db-service-task-
可以自定义线程池优化设计如下:关键代码如下:
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);

 }

 };

 }}
6.注意:

image.png

7. Spring 中业务缓存应用实现

7.1 实现步骤:

1.在实现类上添加注解:@EnableCaching放在启动类上,如下
image.png

2.使用缓存时,也只要在方法上面添加一个注解就可以了,如下:
image.png

3.在更新的方法上面,添加注解@CacheEvict可以清除缓存(增删改):

image.png

4.缓存的使用流程图:
image.png

定义一个异常监控切面,对目标页面方法进行异常监控,并以日志信息的形式输出异常

image.png

总结:1.AOP使用的在业务层:一般使用在实现类里面;


茆先生
4 声望0 粉丝

未来可期--加油