龙空技术网

Java注解、在Spring boot项目中自定义注解解决实际问题

java小悠 278

前言:

眼前咱们对“自定义问题怎么写”都比较看重,大家都想要学习一些“自定义问题怎么写”的相关资讯。那么小编同时在网摘上搜集了一些关于“自定义问题怎么写””的相关知识,希望同学们能喜欢,同学们一起来学习一下吧!

Java注解

在Java中注解其实就是写在接口、类、属性、方法上的一个标签,或者说是一个特殊形式的注释,与普通的注释不同的是:普通注释只是一个注释,而注解在代码运行时是可以被反射读取并进行相应的操作,而如果没有使用反射或者其他检查,那么注解是没有任何真实作用的,也不会影响到程序的正常运行结果。

注解的作用作为特定标记,用于告诉编译器一些信息编译时动态处理,如动态生成代码运行时动态处理,作为额外信息的载体,如获取注解信息注解的分类

注解通常分为三类:

元注解:Java内置的注解,标明该注解的使用范围、生命周期等标准注解:Java提供的基础注解,标明过期的元素/标明是复写父类方法的方法/标明抑制警告自定义注解:第三方定义的注解,含义和功能由第三方来定义和实现元注解

用于定义注解的注解,通常用于注解的定义上,标明该注解的使用范围、生效范围等。元注解主要包含以下五种: @Retention、@Target、@Documented、@Inherited、@Repeatable

@Retention

作用:声明注解的保留周期(生命周期)

该注解的不同参数及效果:

@Retention(RetentionPolicy.SOURCE):只作用在源码阶段,字节码文件中不存在@Retention(RetentionPolicy.CLASS):保留到字节码文件阶段,运行阶段不存在@Retention(RetentionPolicy.RUNTIME):一直保留到运行阶段

@Target

作用:声明被修饰的注解只能在哪些位置使用

该注解的不同参数及效果:

@Target(ElementType.TYPE):被修饰的注解只能在类、接口上使用@Target(ElementType.FIELD):被修饰的注解只能在成员变量上使用@Target(ElementType.METHOD):被修饰的注解只能在成员方法上使用@Target(ElementType.PARAMETER):被修饰的注解只能在方法参数上使用@Target(ElementType.CONSTRUCTOR):被修饰的注解只能在构造器上使用@Target(ElementType.LOCAL_VARIABLE):被修饰的注解只能在局部变量上使用

@Documented

作用:是否在生成的Javadoc文档中体现,被标注该注解后,生成的javadoc中,会包含该注解

@Inherited

作用:是否可以被标注类的子类继承。被@Inherited修饰的注解是具有继承性的,在自定义的注解标注到某个类时,该类的子类会继承这个自定义注解。

@Repeatable

作用:是否可以重复标注

标准注解

Java 中自带且常用的几种标准注解有 @Override、@Deprecated、@SuppresWarninngs、@SafeVarargs

@Override:是一个标记类型注解,用于提示子类要复写父类中被 @Override 修饰的方法,它说明了被标注的方法重载了父类的方法,起到了断言的作用

@Deprecated:也是一个标记类型注解,用于标记过时的元素。比如如果开发人员正在调用一个过时的方法、类或成员变量时,可以用该注解进行标注

@SuppressWarnings :可以阻止警告的提示

@SafeVarargs :是一个参数安全类型注解,它的目的是提醒开发人员,不要用参数做一些不安全的操作

自定义注解

自定义注解的基本格式(修饰符、默认值可缺失):

java复制代码public @interface 注解名 {  修饰符 返回值 属性名() 默认值;  修饰符 返回值 属性名() 默认值;}

定义一个简单的注解示例:

java复制代码// 保留至运行时@Retention(RetentionPolicy.RUNTIME)// 可以加在方法或者类上@Target(value = {ElementType.TYPE,ElementType.METHOD})public @interface RequestMapping {    public String method() default "GET";    String path();}

注解的本质就是一个接口,继承了java.lang.annotation.Annotation

自定义注解在Spring boot项目中的应用实例

在Spring boot框架中,注解给项目开发带来了巨大的方便,使用注解的优势主要有:

采用纯Java代码,不在需要配置繁杂的xml文件在配置中也可享受面向对象带来的好处类型安全对重构可以提供良好的支持减少复杂配置文件的同时亦能享受到Spring IoC容器提供的功能

在Spring boot框架中,同样可以自定义注解并用于优化项目开发,实例如下:

问题描述

在项目业务表中存在以下四个公共字段:

字段名

含义

项目涉及的操作类型

create_time

创建时间

insert

create_user

创建人id

insert

update_time

修改时间

insert/update

update_user

修改人id

insert/update

当创建或修改相关信息时,这几个字段也会做相应的set方法赋值,同时存在着代码冗余、不便于后期维护的问题,为解决这个问题,可以加一个公共字段自动填充的功能

实现思路

公共字段自动填充功能的实现思路:

自定义注解@AutoFill,用于标识需要进行公共字段自动填充的方法自定义切面类AutoFillAspect,统一拦截加入了@AutoFill注解的方法,通过反射为公共字段赋值在Mapper的方法上加上@AutoFill注解

用到的知识点:枚举、注解、AOP、反射

自定义注解@AutoFill

首先定义一个枚举类,用于作为@AutoFill的参数即数据库操作类型:

java复制代码public enum OperationType {    // 更新操作    UPDATE,    //插入操作    INSERT}

然后自定义注解@AutoFill:

java复制代码@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface AutoFill {    //数据库操作类型:UPDATE INSERT,OperationType在枚举类中定义    //写法:@AutoFill(value = OperationType.UPDATE)、@AutoFill(value = OperationType.INSERT)    OperationType value();}
自定义切面类AutoFillAspect
java复制代码@Aspect@Component@Slf4jpublic class AutoFillAspect {    //切入点,切入点在com.sky.mapper.*.*(..)且有注解@AutoFill下的方法执行    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")    public void autoFillPointCut(){}    //前置通知,在通知中进行公共字段的赋值    @Before("autoFillPointCut()")    public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        log.info("开始进行公共字段自动填充");        //获取到当前被拦截的方法上的数据库操作类型(UPDATE/INSERT)        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){            //为四个公共字段赋值            Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);            Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);            Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);            Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);            //通过反射为对象赋值            setCreateTime.invoke(entity,now);            setCreateUser.invoke(entity,currentId);            setUpdateTime.invoke(entity,now);            setUpdateUser.invoke(entity,currentId);        }else if(operationType == OperationType.UPDATE){            //为两个公共字段赋值            Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);            Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);            //通过反射为对象赋值            setUpdateTime.invoke(entity,now);            setUpdateUser.invoke(entity,currentId);        }    }}
在相关方法上加上@AutoFill
java复制代码    @AutoFill(value = OperationType.INSERT)    void insert(Employee employee);    @AutoFill(value = OperationType.UPDATE)    void update(Employee employee);

原文链接:

标签: #自定义问题怎么写