首页 > 其他分享 >diy-aop

diy-aop

时间:2024-09-19 19:46:17浏览次数:9  
标签:void entity class Pointcut diy aop 注解 public

不得了,看到自定义aop,这下终于知道它有啥作用了,这玩意确实好用

做sky-takeout的时候,没有几集就涉及到公共字段的自动赋值,例如createUser、createTime之类的。很容易可以想到,利用类似‘拦截器’的东西就可以实现,但是具体怎么做呢?所以先介绍下通用的流程步骤:

1.声明自定义注解

1.1 元注解 - 注解的注解

@Target 注解可声明位置

  • ElementType.PACKAGE:该注解只能声明在一个包名前。

  • ElementType.ANNOTATION_TYPE:该注解只能声明在一个注解类型前。

  • ElementType.TYPE:该注解只能声明在一个类前。

  • ElementType.CONSTRUCTOR:该注解只能声明在一个类的构造方法前。

  • ElementType.LOCAL_VARIABLE:该注解只能声明在一个局部变量前。

  • ElementType.METHOD:该注解只能声明在一个类的方法前。

  • ElementType.PARAMETER:该注解只能声明在一个方法参数前。

  • ElementType.FIELD:该注解只能声明在一个类的字段前。

@Retention保留/注解声明周期

  • RetentionPolicy.SOURCE : 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;

  • RetentionPolicy.CLASS : 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;

  • RetentionPolicy.RUNTIME : 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

对于@Target我没有意见,但是对于@Retention我不明白,Source和Class级别的声明周期有什么用呢?

看到一个回答:‘源代码级别的注解有两个作用,一是作为文档的补充,给人看的,比如@Override,二是作为源代码生成器的材料,比如ButterKnife框架(不懂)’

懂了一些了,所以目前对于业务级别的开发,应该一般就是Runtime界别的

1.2 示例:

/**
 * 自定义注解,用于标识某个方法需要进行公共字段自动填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) 
public @interface AutoFill {
    //数据库操作类型:UPDATE INSERT
    OperationType value();
}

2.声明自定义切面

2.1 注解介绍

@Aspect:作用是把当前类标识为一个切面供容器读取
@Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: final增强,不管是抛出异常或者正常退出都会执行

2.2 切入点注解语法

    /**
     * 1、使用within表达式匹配
     * 下面示例表示匹配com.leo.controller包下所有的类的方法
     */
    @Pointcut("within(com.leo.controller..*)")
    public void pointcutWithin(){

    }

    /**
     * 2、this匹配目标指定的方法,此处就是HelloController的方法
     */
    @Pointcut("this(com.leo.controller.HelloController)")
    public void pointcutThis(){

    }

    /**
     * 3、target匹配实现UserInfoService接口的目标对象
     */
    @Pointcut("target(com.leo.service.UserInfoService)")
    public void pointcutTarge(){

    }

    /**
     * 4、bean匹配所有以Service结尾的bean里面的方法,
     * 注意:使用自动注入的时候默认实现类首字母小写为bean的id
     */
    @Pointcut("bean(*ServiceImpl)")
    public void pointcutBean(){

    }

    /**
     * 5、args匹配第一个入参是String类型的方法
     */
    @Pointcut("args(String, ..)")
    public void pointcutArgs(){

    }

    /**
     * 6、@annotation匹配是@Controller类型的方法
     */
    @Pointcut("@annotation(org.springframework.stereotype.Controller)")
    public void pointcutAnnocation(){

    }
    /**
     * 7、@within匹配@Controller注解下的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.CLASS)
     */
    @Pointcut("@within(org.springframework.stereotype.Controller)")
    public void pointcutWithinAnno(){

    }
    /**
     * 8、@target匹配的是@Controller的类下面的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.RUNTIME)
     */
    @Pointcut("@target(org.springframework.stereotype.Controller)")
    public void pointcutTargetAnno(){

    }
    /**
     * 9、@args匹配参数中标注为@Sevice的注解的方法
     */
    @Pointcut("@args(org.springframework.stereotype.Service)")
    public void pointcutArgsAnno(){

    }


    /**
     * 10、使用excution表达式
     * execution(
     *  modifier-pattern?           //用于匹配public、private等访问修饰符
     *  ret-type-pattern            //用于匹配返回值类型,不可省略
     *  declaring-type-pattern?     //用于匹配包类型
     *  name-pattern(param-pattern) //用于匹配类中的方法,不可省略
     *  throws-pattern?             //用于匹配抛出异常的方法
     * )
     *
     * 下面的表达式解释为:匹配com.leo.controller.HelloController类中以hello开头的修饰符为public返回类型任意的方法
     */
    @Pointcut(value = "execution(public * com.leo.controller.HelloController.hello*(..))")
    public void pointCut() {

    }

2.3 示例:

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段自动填充...");

        //获取到当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autoFill.value();//获得数据库操作类型

        //获取到当前被拦截的方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if(args == null || args.length == 0){
            return;
        }

        Object entity = args[0];

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if(operationType == OperationType.INSERT){
            //为4个公共字段赋值
            try {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else if(operationType == OperationType.UPDATE){
            //为2个公共字段赋值
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.添加注解

...
	/**
     * 新增分类
     * @param category
     */
    @Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user) " +
            "VALUES " +
            "(#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
    @AutoFill(value = OperationType.INSERT)
    void insert(Category category);
...

标签:void,entity,class,Pointcut,diy,aop,注解,public
From: https://www.cnblogs.com/yuqiu2004/p/18421216

相关文章

  • Spring AOP
    1.什么是AOPAOP(Aspect-OrientedProgramming)中文翻译为面向切面编程,面向方面编程在AOP中,可以理解为就是面向方法编程2.AOP的应用场景我们这里有一个项目,项目中开发了很多的业务功能然而有一些业务功能执行效率比较低,执行耗时较长,我们需要针对于这些业务方法进行优化。那......
  • spring 详细讲解(ioc,依赖注入,aop)
    Spring框架既可以从广义和狭义两个角度理解,下面讲解这两个层面的概念:(本文主要讲解的是狭义上的spring,广义上的简单概括)1、spring的含义1.广义上的Spring从广义上讲,Spring是一个涵盖多个模块的企业级应用开发框架,它提供了从基础架构到复杂企业应用开发所需的全面解......
  • 基于django+vue电脑DIY微信小程序演示录像22023【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着科技的飞速发展,个人电脑(PC)已成为人们日常生活与工作中不可或缺的一部分。然而,在市场上琳琅满目的电脑配件和复杂多变的配置选项中,许多......
  • 基于django+vue电脑DIY微信小程序【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着科技的飞速发展,个人电脑已成为日常生活与工作中不可或缺的工具。而电脑DIY(自己动手组装电脑)作为一种新兴的文化和趋势,不仅满足了用户......
  • AOP失效场景总结
    AOP(面向切面编程)在Spring中是通过动态代理机制来实现的,但在某些情况下,AOP可能会失效。以下是常见的几种AOP失效的场景及原因:1.内部方法调用原因:当类中的一个方法调用同一个类中的另一个方法时,AOP不会生效。解释:SpringAOP是基于代理的实现,只有通过代理对象调用方法时,......
  • Spring AOP
    AOP原理面向切面(AspectOrientProgramming)面向切面编程,是面向对象编程(OOP)的一种补充。在Java程序自上而下处理主业务时,也会经常处理一些和主业务逻辑无关的问题(比如在接收用户访问请求时,计算程序响应该请求的运行时间)。这些代码如果和主逻辑代码混淆,会导致后期难以......
  • Spring6详细学习笔记(IOC+AOP)
    一、Spring系统架构介绍1.1、定义Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。Spring官网Spring是一款主流的JavaEE轻量级开源框架,目的是用于简化Java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何Java应用都可以从S......
  • 【Java】已解决:org.aopalliance.aop.AspectException
    文章目录一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项已解决:org.aopalliance.aop.AspectException一、分析问题背景在使用SpringAOP(面向切面编程)时,开发者有时会遇到org.aopalliance.aop.AspectException报错。这通常发生......
  • 【转载】【深度学习服务器组装】【DIY土豪級別電腦】1.5TB記憶體192核心384線程雙路EP
    视频地址:https://www.youtube.com/watch?v=_VMvGuVGI1M......
  • 解决在.net8 WebAPI中 AOP 使用AbstractInterceptorAttribute
    在网上找了许多例子但是放在.net8就不好使了比如在Program中配置IInterceptor或者 services.ConfigureDynamicProxy,网上说的对但是也不全对//通过单元测试(MSTest)//创建IServiceCollectionIServiceCollectionservices=newServiceCollection(); 是能调用Abstr......