如何丝滑地剥离与业务无关的操作?AOP真的懂你

AOP的业务应用

AOP+线程池实现日志异步入库功能

1.导入AOP依赖
<dependency>     
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.创建业务切面对象

2.1创建注解类型

示例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
       String operation();
}

2.2创建切面对象

示例:

@Aspect
@Component
public class SysLogAspect {
    /**
     * @Pointcut注解用于定义切入点
     * @annotation(定义注解的全路径)为切入点表达式,后续由此注解描述的方法为切入
     * 点方法
     */
   @Pointcut("@annotation(com.cy.jt.common.annotation.RequiredLog)")
    public void doLog(){}//此方法只负责承载切入点的定义

    /**
     * @Around注解描述的方法,可以在切入点执行之前和之后进行业务拓展,
     * @param jp 连接点对象,此对象封装了要执行的目标方法信息.
     * 可以通过连接点对象调用目标方法.
     * @return 目标方法的执行结果
     * @throws Throwable
     */
    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint jp)throws Throwable{
    }
   

2.3通过注解描述业务方法,此时这个方法为日志切入点方法

示例:

@RequiredLog(operation="公告查询")
@GetMapping
public JsonResult doSelectNotices(SysNotice sysNotice){....}

AOP的底层就是动态代理的实现,所以回顾一下动态代理的内容.

3.回顾动态代理知识点
动态代理方式对比
JDK动态代理1.要求被代理者,必须实现接口.
2.代理对象根据接口的类型,通过反射机制创建出来一个实现类对象.(JDK源码底层实现的)
3.Spring容器面向接口注入时 ,默认条件下采用JDK动态代理的方式实例化对象.
Cglib动态代理1.CGLIB是JDK代理的一种补充.
2.不管被代理者是否实现接口,都可以为其创建代理对象
3.代理对象是被代理者的子类.(AOP默认采用Cglib代理)
4.利用反射获取类中资源
 //ProceedingJoinPoint 连接点
private void doLogInfo(ProceedingJoinPoint jp,
                           ...)
            throws Exception {
      
        //1.3获取操作名(operation)-@RequiredLog注解中value属性的值
        //1.3.1获取目标对象类 
        Class<?> targetCls=jp.getTarget().getClass();
    
        //1.3.2获取目标方法
       //先获取方法签名
        MethodSignature ms=
                (MethodSignature) jp.getSignature();
    	//利用目标对象类获取目标方法
        Method targetMethod=targetCls.getMethod(
                ms.getName(),ms.getParameterTypes());
        //1.3.3 获取方法上RequiredLog注解
        RequiredLog annotation =
                targetMethod.getAnnotation(RequiredLog.class);
        //1.3.4 获取注解中定义的操作名
        String operation=annotation.operation();
        //1.4获取方法声明(类全名+方法名)
        String classMethodName=
                targetCls.getName()+"."+targetMethod.getName();
        //1.5获取方法实际参数信息
        Object[]args=jp.getArgs();
    	//将参数对象序列化
        String params=new ObjectMapper().writeValueAsString(args);
       ....
      
    }

}
5.配置线程池

线程池的配置:(实例)

spring:
  task:
    #springboot中线程池的配置
    execution:
      pool:
      	//core-size :核心线程数
        core-size: 8
        
        //queue-capacity:队列容量
        queue-capacity: 512
        
        //max-size: 最大线程数
        max-size: 128
        
        //keep-alive:线程空闲时间
        keep-alive: 60000
        
        //thread-name-prefix:线程名的前缀
      thread-name-prefix: aysnc-service-task-
//说明:
//core-size :核心线程数,当池中线程数没达到core-size的值时,每接收一个新的任务都会创建一个新线程,然后存储到池。假如池中线程数已经达到core-size设置的值,再接收新的任务时,要检测是否有空闲的核心线程,假如有,则使用空闲的核心线程执行新的任务。

//queue-capacity:队列容量,假如核心线程数已达到core-size设置的值,并且所有的核心线程都在忙,再来新的任务,会将任务存储到任务队列。

//max-size: 最大线程数,当任务队列已满,核心线程也都在忙,再来新的任务则会创建新的线程,但所有线程数不能超过max-size设置的值,否则可能会出现异常(拒绝执行)

//keep-alive:线程空闲时间,假如池中的线程数多余core-size设置的值,此时又没有新的任务,则一旦空闲线程空闲时间超过keep-alive设置的时间值,则会被释放。

//thread-name-prefix:线程名的前缀,项目中设置线程名的目的主要是为了对线程进行识别,一旦出现线程问题,可以更好的定位问题。
6.异步实现日志写入数据库:

6.1启动异步


@EnableAsync
@SpringBootApplication
public class SystemApplication {

    public static void main(String[] args) {
        SpringApplication.run(DbpmsApplication.class, args);
    }
}

6.2定义切入点方法

@Async
public void saveLog(SysLog entity){
  sysLogDao.insertLog(entity);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七老板的blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值