springboot中使用AOP+发布订阅实现功能模块解耦

业务场景:开发一个计算接口,接口需要从FTP中下载报表文件进行解析,返回计算数据,同时生成检测报告上传至指定ftp。
此业务中包含以下几个动作:
1.登录FTP下载文件到本地;
2.解析文件;
3.生成自检报告并上传到指定ftp,并以邮件形式通知客户;
4.重置服务本地文件夹信息,防止数据混乱.
5.返回解析数据结果;

最初版本是线性同步作业:1—>2—>3—>4—>5,正常情况下除了接口响应速度慢,功能基本没有问题,但是在邮件发送或重置文件夹信息抛出异常时,接口无法正常返回数据;
版本2,将自检报告上传、邮件发送、重置文件夹信息提交到线程池,进行异步执行,提高了接口响应速度,解决了邮件发送或重置文件夹信息抛出异常时,接口无法正常返回数据的问题。但是实际生产中出现了因文件格式异常产生计算错误,导致服务抛出异常,第4步重置文件夹动作未执行,后续再次请求时数据混乱的问题;
版本3:使用自定义注解,配合AOP,在接口执行后拦截(后置通知增强),当方法执行完后(无论是否抛出异常都会执行),发布自定义计算完成事件,在监听器中执行重置本地文件夹方法,这样解耦更彻底,即使计算方法出错,文件夹相关信息也会被清除,不会造成下一次计算数据混乱。
1.自定义注解

package com.weige.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD}) // 表示该注解只能用来修饰在方法上
public @interface initFileInfo {
    Class businessType() default Object.class;//类类型属性
    String value() default "重置文件信息";
}

2.切面配置

package com.weige.aspect;



import com.weige.config.SBLCompleteEvent;

import com.weige.vo.SBLRequestParam;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;


/**
 * @author 
 * @version 1.0
 * @description: 日志切面
 * @date 2021/9/27 15:52
 */
@Aspect
@Component
public class InitFileInfoAspect {
    Logger logger = LoggerFactory.getLogger(InitFileInfoAspect.class);
    @Autowired
    ApplicationContext applicationContext;
    //定义切点
    @Pointcut("execution(public * com.weige.controller.*.*(..))")
    public void webLog(){}


    @Before("webLog()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
      

    }

 

    //后置异常通知
    @AfterThrowing("webLog()")
    public void throwss(JoinPoint jp){

//        System.out.println("方法异常时执行啦,.....");
    }

    //这里使用后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
    @After("webLog()")
    public void after(JoinPoint jp){
        Object obj=jp.getArgs()[0];
        if(obj instanceof SBLRequestParam){
            SBLRequestParam sblRequestParam=(SBLRequestParam)obj;
            String lotid=sblRequestParam.getLotId();
            //事件发布(如果不配置异步支持,流程会阻塞到这里,
            //监听事件完成后流程才会往下走)
            applicationContext.publishEvent(new SBLCompleteEvent(this, lotid));
        }



    }


}

3.自定义事件

package com.weige.config;

import org.springframework.context.ApplicationEvent;

/**
 * @author 
 * @version 1.0
 * @description: 自定义事件:SBL计算完成
 * @date 2021/12/2 13:51
 */
public class SBLCompleteEvent extends ApplicationEvent {
    private String lotId;

    public String getLotId() {
        return lotId;
    }

    public void setLotId(String lotId) {
        this.lotId = lotId;
    }

    public SBLCompleteEvent(Object source,String lotId) {
        super(source);
        this.setLotId(lotId);
    }
}

4.自定义监听器,监听指定事件

package com.weige.config;

import com.weige.service.business.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.File;
import java.lang.reflect.InvocationTargetException;




/**
 * @author 
 * @version 1.0
 * @description: 自定义事件监听器
 * @date 2021/7/28 15:16
 */
@Component
@Async
public class SblCompleteListener {
    @Value("${localDirPath}")
    private  String localDirPath;

    @Autowired
    FileService fileService;
/**
     * 注册监听实现方法
     * 只需要让监听类被Spring管理即可,@EventListener注解会根据方法内配置的事件完成监听。
     * 接下来可启动项目来测试事件发布时是否被监听者所感知
     *
     * @param
     */


    @EventListener
    @Order(1)
    public void initDir(SBLCompleteEvent sblCompleteEvent) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        System.out.println("我监听到SBLP计算完了,准备删除对应文件:"+sblCompleteEvent.getLotId());
        // 获取注册用户对象
        String lotId = sblCompleteEvent.getLotId();
        //执行删除动作
        fileService.deleteFile(new File(localDirPath),lotId);
        System.out.println("终于删除成功了。。。。");

    }


}

以上是工作过程中处理问题的一些思路,特此记录。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值