• JAVA【注解】 自定义注解


    一、注解的概念

    注解(也被称为元数据 )为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

    注解的语法比较简单,除了@符号的使用之外,它基本与Java固有的语法一致。Java SE5内置了三种,定义在java.lang中的注解:

    ·@Override,表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误,或者方 法签名对不上被覆盖的方法,编译器就会发出错误提示。
    ·@Deprecated,如果程序员使用了注解为它的元素,那么编译器会发出警告信息。
    ·@Suppress Warnings,.关闭不当的编译器警告信息。在Java SE5之前的版本中,也可以使 用该注解,不过会被忽略不起作用。
    Java还另外提供了四种注解,专门负责新注解的创建。稍后我们将学习它们。

    二、注解的基本语法

    2.1 自定义注解

    1. 用@interface关键字来声明注解,注解也会生成.class文件
    2. 注解可以有成员变量,在使用注解的时候要给成员变量赋值。可以使用default来定义默认值。
      用以下方式来声明成员变量
      ·成员类型成员名();
    3. 成员类型可以为基本数据类型、String、Class、enum、Annotation,以及相应的数组
    4. 如果只有一个成员,成员名通常用value。
    5. 使用时必须指定参数值,除非它有默认值。格式是“参数名=参数值”,如果只有一个参数
      成员,且名称为value,可以直接写“参数值”
    6. 没有成员变量的注解也称为标记,有成员变量的注解称为元数据注解
    7. 举例
      ·写一个lyAnnotation注解,体会以上概念
    package com.qf;
    
    public @interface MyAnnotation {
        int id() default 0;
        String name() default "zhang san" ;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
     @MyAnnotation(id = 22,name="李四")
        public void test2(){
    
        }
    
    • 1
    • 2
    • 3
    • 4

    2.2 元注解

    Java目前只内置了四种元注解。元注解专职负责注解其他的注解:

    元注解作用
    @Target表示该注解可以用于什么地方。可能的ElementType参数包括:
    CONSTRUCTOR:构造器的声明
    FIELD:域声明(包括enum实例)
    LOCAL_VARIABLE:局部变量声明
    METHOD:方法声明
    PACKAGE:包声明
    PARAMETER:参数声明
    TYPE:类、接口(包括注解类型)或enum声明
    @Retention表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
    SOURCE:注解将被编译器丢弃。
    CLASS:注解在class-文件中可用,但会被VM丢弃。
    RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
    @Documented将此注解包含在Javadoc中。
    @Inherited允许子类继承父类中的注解。

    三、编写注解处理器解析注解

    ·编写注解处理器解析注解

    1. 使用注解主要目的就是为了可以读取注解并进行使用
    2. 在注解处理器中,可以使用反射机制来从使用注解的类中读取这个类的结构信息(属性,方
      法,构造器等),并可以获取注解的信息,进行动态处理(运行时对这些信息进行处理)。
    3. 举例
      ·创建一个注解,注解名为Parse,定义两个成员,String name和int age。这个注解用于
      放到方法声明前。编写一个注解处理器,要求打印出“name,您的xxx方法写的真好,能
      够age岁就写出来,真是年轻有为。”

    注解

    package com.qf;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Parse {
        int age() default 18;
        String name() ;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    反射

    package com.qf;
    
    import java.lang.reflect.Method;
    
    public class Test3 {
        public static void main(String[] args) {
           Class<Test3> test3Class= Test3.class;
            for (Method method : test3Class.getMethods()) {
                Parse annotation = method.getAnnotation(Parse.class);
                if (annotation!=null){
                    System.out.printf("%s,您的%s方法写的可真好,您今年才%d岁就写出来,真是年轻有为",annotation.name(),method.getName(),annotation.age());
                    System.out.println();
                }
            }
        }
        
        @Parse(name="张三")
        public void test1(){
    
        }
    
        @Parse(age = 22,name="李四")
        public void test2(){
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    四、反射

    4.1 反射的概念

    使用反射机制可以动态获取当前class的信息 比如方法的信息、注解信息、方法的参数、属性等;

    4.2 反射技术应用的场景

    1. JDBC加载驱动连接 class.forname
    2. Spring容器框架IOC实例化对象
    3. 自定义注解生效(反射+Aop)
    4. 第三方核心的框架

    4.3 反射技术的使用

    Class类 代表类的实体,在运行的Java应用程序中表示类和接口
    Field类 代表类的成员变量(成员变量也称为类的属性)
    Method类 代表类的方法
    Constructor类 代表类的构造方法

    4.4 使用反射机制初始化对象 获取当前class的信息

    Class<?> aClass = Class.forName(“com.mayikt.entity.UserEntity”);

    4.5 执行无参数构造函数

    Class<?> aClass = Class.forName("com.qf.entity.UserEntity");
    UserEntity userEntity = (UserEntity) aClass.newInstance();
    userEntity.setName("zhangsan");
    userEntity.setUserId(1234);
    System.out.println(userEntity);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.6 执行有参数构造函数

    Class<?> aClass = Class.forName("com.qf.entity.UserEntity");
    // 执行有参数构造函数
    Constructor<?> constructor = aClass.
            getConstructor(Integer.class, String.class);
    UserEntity userEntity = (UserEntity) constructor.
            newInstance(10, "zhangsan");
    System.out.println(userEntity);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.7 使用反射机制给属性赋值

    Class<?> aClass = Class.forName("com.qf.entity.UserEntity");
    // 给私有属性赋值
     UserEntity  userEntity = (UserEntity) aClass.newInstance();
     Field userId = aClass.getDeclaredField("userId");
     userId.setAccessible(true);		//关闭安全检查,直接通行
     userId.set(userEntity,12);
     Field name = aClass.getDeclaredField("name");
     name.setAccessible(true);
     name.set(userEntity,"zhangsan");
     System.out.println(userEntity);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    假设未设置setAccessible(true),不能通过java语言安全检查,因为你需要访问的是类的私有属性和方法

    Exception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.Test001 can not access a member of class com.mayikt.entity.UserEntity with modifiers "private"
    	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    
    
    • 1
    • 2
    • 3
    • 4

    如果使用反射给私有属性或者调用私有的方法 都需要设置权限

    4.8 使用反射机制给调用方法

      Class<?> aClass = Class.forName("com.qf.entity.UserEntity");
    // 给私有属性赋值
     UserEntity  userEntity = (UserEntity) aClass.newInstance();
     Method mete= aClass.getDeclaredMethod("mete", Integer.class);
     mete.setAccessible(true);
     Object invoke = mete.invoke(userEntity, 10);
     System.out.println(invoke);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    五、自定义注解综合案例(声明式事务—注解+aop+反射)

    5.1、Transational注解的痛点

        @Transactional
        public void insertUser()  {
            try {
                user user=new user(new Date(),"place",new Date());
                userDao.insert(user);
                int i=1/0;
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    当我们需要在事务控制的service层类中使用try catch 去捕获异常后,就会使事务控制失效,因为该类的异常并没有抛出,就不是触发事务管理机制。怎样才能即使用try catch去捕获异常,而又让出现异常后spring回滚呢,这里就要用到,在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常了
    例如

       @Transactional
        public void insertUser()  {
            try {
                user user=new user(new Date(),"place",new Date());
                userDao.insert(user);
                int i=1/0;
            }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                e.printStackTrace();
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    痛点:每次使用try catch块时,都需要加入 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();手动回滚,代码多重复

    5.2、声明式事务—注解+aop+反射

    注解

    package com.qf;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExTransational {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    手动事务

    package com.qf;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
    
    @Component
    public class TransactionalUtils {
    
        @Autowired
        private DataSourceTransactionManager dataSourceTransactionManager;
    
        /**
         * begin
         * @return
         */
        public TransactionStatus begin(){
            // 设置传播行为
            TransactionStatus transaction =
                    dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
            return transaction;
        }
    
        /**
         * 提交
         * @param transaction
         */
        public void commit( TransactionStatus transaction){
            dataSourceTransactionManager.commit(transaction);
    
        }
    
        /**
         * 回滚
         * @param transaction
         */
        public void rollback(TransactionStatus transaction){
            dataSourceTransactionManager.rollback(transaction);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    Aop切面类

    package com.qf;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.TransactionStatus;
    
    
    @Component
    @Aspect
    public class ExTransationAop {
    
        @Autowired
        private TransactionalUtils transactionalUtils;
        @Around(value = "@annotation(com.qf.ExTransational)")
        public Object reflect(ProceedingJoinPoint joinPoint){
            TransactionStatus begin =null;
            try {
                begin = transactionalUtils.begin();
                Object result = joinPoint.proceed();
                transactionalUtils.commit(begin);
                return result;
            } catch (Throwable throwable) {
                if (begin!=null){
                    transactionalUtils.rollback(begin);
                }
                throwable.printStackTrace();
            }
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    最终效果

        @ExTransational
        public void insertUser()  {
                user user=new user(new Date(),"place",new Date());
                userDao.insert(user);
                int i=1/0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

  • 相关阅读:
    《python 数据可视化基础》第三章 散点图 scatter
    面试复习题--gradle插件
    定时同步之Martin Oerder算法原理与公式推导
    Flink中的Window计算-增量计算&全量计算
    Mybatis架构,SqlSessionFactory源码分析
    单卡显存不足时如何进行多卡推理?
    算法金 | 突破最强算法模型,决策树算法!!
    Linux编译宏BUILD_BUG_ON_ZERO
    【MySQL】面试题
    Android架构师学习必备学习宝典《Android架构开发手册》
  • 原文地址:https://blog.csdn.net/cativen/article/details/125436789