注解使用

01_注解介绍

  • 概念
    • 就是一个修饰符
  • 特点
    • 是JDK5.0之后引入的特性。以“@注解名”形式存在
  • 作用
    • 跟踪代码依赖性
    • 执行编译时格式检查
    • 代替已有的配置文件

02_java内置注解

  • @Overirde

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    	public @interface Override {
    }
    
    • 标记指定方法是一个重写方法,否则报错
  • @Deprecated

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
    public @interface Deprecated {
    }
    
    • 标记一个类、字段、方法是一个过时的!
  • @SuppressWarings

    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    
    • value : 注解所压制的警告的类型

      unchecked 未检查的转化,如集合没有指定类型还添加元素
      unused 未使用的变量
      resource 有泛型未指定类型
      path 在类路径,原文件路径中有不存在的路径
      deprecation 使用了某些不赞成使用的类和方法
      fallthrough switch语句执行到底没有break关键字
      rawtypes 没有写泛型,比如: List list = new ArrayList();
      all 全部类型的警告
      

      用的最多是all

03_注解分类

  • 注解分类
    • 标记注解
      • 注解中没有属性
      • 比如:@Override、@Deprecated
    • 单值注解
      • 注解中只有一个属性
      • 比如:@SuppressWarings
    • 完整注解
      • 注解中有多个属性

04_自定义注解

  • 格式

    public @interface 注解名 {
        数据类型 属性名1() default 默认值1;
        数据类型 属性名2() ;
    }
    
  • 基本使用

    public @interface MyAnnotation01 {
    
        String username() default "root";
        String password() default "root123";
        int age() default 16;
        String value();
    
    }
    
  • 注意事项

    • value属性单独使用时,是可以省略"value="。

05_元注解概述

  • 概述

    • 作用在自定义注解上,规定自定义注解的作用区域、存活策略!
  • 常用的元注解

    • @Target

      • 规定自定义注解的作用区域

        TYPE:类、接口、注解、枚举
        FIELD:成员你变量
        METHOD:成员方法
        PARAMETER:形参
        CONSTRUCTOR:构造器
        LOCAL_VARIABLE:局部变量
        ANNOTATION_TYPE:注解类型
        PACKAGE:
    • @Retention

      • 规定自定义注解的存活策略

        SOURCE : 仅存活在源码
        CLASS : 存活在编译期
        RUNTIME : 存活在运行时
        

    06_元注解使用

  • @Target

    • 定义
    @Target(value = {
            ElementType.TYPE ,
            ElementType.FIELD ,
            ElementType.METHOD ,
            ElementType.PARAMETER ,
            ElementType.LOCAL_VARIABLE }
            )
    public @interface MyAnnotation01 {
    
        String value() default "hello annotation";
    
    }
    
    • 使用
    @MyAnnotation01
    public class Demo01 {
    
        @MyAnnotation01
        private int num = 1;
    
        @MyAnnotation01
        public static void main(@MyAnnotation01 String[] args) {
    
            @MyAnnotation01
            int num = 1;
        }
    
    }
    
  • @Retention

    • 定义
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation01 {
    
        String value() default "hello annotation";
    
    }
    
    • 一般情况下,注解存活策略是RUNTIME,什么原因?
      • 注解要起作用,必须结合反射使用,而反射是在程序运行时(RUNTIME)执行!

06_自定义注解@MyTest

  • 需求

    • 测试类中,方法上如果使用了@MyTest注解,该方法就会执行!
  • 开发步骤

    • 自定义注解@MyTest
    • 在测试类Test01上使用@MyTest
    • 让@MyTest注解生效
      • 获取到Test01类对应的Class对象
      • 获取Test01类中的所有方法
      • 判断方法上是否有@MyTest注解
        • 如果有,就将该方法执行
        • 如果没有,就不处理
  • 代码实现

    • @MyTest注解
      • @MyTest的存活策略必须是RUNTIME
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyTest {
        String value() default "";
    }
    
    • Test01测试类
    public class Test01 {
    
        @Test
        public void test01(){
            System.out.println("test01");
        }
    
        @MyTest
        public void test02(){
            System.out.println("test02");
        }
    
        @MyTest
        public void test03(){
            System.out.println("test03");
        }
    
        public void test04(){
            System.out.println("test04");
        }
    
    }
    
    • demo类
    public class Demo02 {
    
        public static void main(String[] args) {
            //使用反射,扫描Test01类里面有哪些方法有@MyTest注解
            //如果有@MyTest注解,就将起执行
            //如果没有@MyTest注解,不做任何处理
    
            //1,获取Test01类对应的Class对象
            Class<Test01> clazz = Test01.class;
            //2,获取Test01类下所有的方法对象
            Method[] methods = clazz.getMethods();
            //stream流 lambda表达式
            Arrays.stream(methods).forEach(method -> {
                //method就是单个方法对象
                //3,判断方法上是否有@MyTest注解
                boolean present = method.isAnnotationPresent(MyTest.class);
                if (present) {
                    //方法上有@MyTest注解,执行方法
                    try {
                        method.invoke(clazz.newInstance());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    //方法上没有@MyTest注解
                }
            });
    
        }
    
    }
    

07_自定义注解@JDBCInfo

  • 需求

    • 使用注解@JDBCInfo替代jdbc.properties配置文件
  • 开发步骤

    • 自定义注解@JDBCInfo
    • 在JDBCUtils工具类上使用@JDBCInfo
    • 在JDBCUtils工具类中静态代码块中,获取@JDBCInfo注解上的属性,并给JDBCUtils工具类中成员变量赋值
  • 代码实现

    • 自定义注解@JDBCInfo
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface JDBCInfo {
    
        String driverClass() default "com.mysql.jdbc.Driver";
        String jdbcUrl() default "jdbc:mysql://localhost:3306/day53";
        String user() default "root";
        String password() default "root123";
    
    
    }
    
    • 在JDBCUtils工具类上使用@JDBCInfo
      • 反射读取注解@JDBCInfo中的内容
    @JDBCInfo(password = "root")
    public class JDBCUtils {
    
        private static final String DRIVERCLASS ;
        private static final String JDBCURL;
        private static final String USER;
        private static final String PASSWORD;
    
        static {
            Class<JDBCUtils> clazz = JDBCUtils.class;
            boolean present = clazz.isAnnotationPresent(JDBCInfo.class);
            if (present) {
                //JDBCUtils类上有@JDBCInfo注解,获取该注解
                JDBCInfo jdbcInfo = clazz.getAnnotation(JDBCInfo.class);
                //从@JDBCInfo注解获取driverClass、jdbcUrl、user、password属性值
                DRIVERCLASS = jdbcInfo.driverClass();
                JDBCURL = jdbcInfo.jdbcUrl();
                USER = jdbcInfo.user();
                PASSWORD = jdbcInfo.password();
            } else {
                //JDBCUtils类上没有@JDBCInfo注解,从properties文件
                DRIVERCLASS = "";
                JDBCURL = "";
                USER = "";
                PASSWORD = "";
            }
        }
    }
    
    

08_反射、注解、设计模式初级版

  • 开发步骤

    • 自定义注解@SystemLog
      • className
      • methodName
    • 定义一个UserDao接口,且在该接口使用注解@SystemLog
    • 编写装饰者设计模式
      • 获取UserDao实现子类的Class对象
      • 获取UserDao接口的Class对象
      • 获取UserDao接口中的方法对象
  • 代码实现

    • 自定义注解@SystemLog

      • 注解存活策略:RUNTIME
      @Retention(RetentionPolicy.RUNTIME)
      public @interface SystemLog {
      
          String className();//记录类名
          String methodName();//记录方法名
      
      }
      
    • 定义一个UserDao接口,且在该接口使用注解@SystemLog

      • 设置@SystemLog中className属性、methodName属性
      public interface UserDao {
      
          @SystemLog(className = "com.dao.UserDao" , methodName = "addUser")
          void addUser() throws Exception;
      
          void deleteUser() throws Exception;
      
          @SystemLog(className = "com.dao.UserDao" , methodName = "updateUser")
          void updateUser() throws Exception;
      
      }
      
    • 编写装饰者设计模式

      public class UserDaoWrapper implements UserDao{
      
          private UserDao userDao;
      
          public UserDaoWrapper(UserDao userDao) {
              this.userDao = userDao;
          }
      
          @Override
          public void addUser() throws Exception {
              userDao.addUser();
              printLog("addUser");
          }
      
          @Override
          public void deleteUser() throws Exception {
              userDao.deleteUser();
              printLog("deleteUser");
          }
      
          @Override
          public void updateUser() throws Exception {
              userDao.updateUser();
              printLog("updateUser");
          }
      
          /**
           * 日志记录
           * @param runMethodName
           */
          private void printLog(String runMethodName) throws Exception {
              //判断接口上对应的方法中是否有@SystemLog注解
              //获取UserDao接口实现子类的Class对象
              Class<? extends UserDao> sonClazz = userDao.getClass();
              //获取UserDao接口的Class对象
              Class<?>[] interfaces = sonClazz.getInterfaces();
              Class<?> fatherClazz = interfaces[0];
              //获取接口中对应的方法对象(addUser方法) 
              Method method = fatherClazz.getMethod(runMethodName);
              if (null !=  method) {
                  //判断方法上是否有@SystemLog注解
                  boolean present = method.isAnnotationPresent(SystemLog.class);
                  if (present) {
                      //方法有@SystemLog注解,打印日志
                      SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
                      Date currentDate = new Date();
                      String currentTimeStr = format.format(currentDate);
                      SystemLog systemLog = method.getAnnotation(SystemLog.class);
                      String className = systemLog.className();
                      String methodName = systemLog.methodName();
                      System.out.println(currentTimeStr + " --- " + className + "类中 ---" + methodName + "()方法 --- 运行了");
                  }
              }
      
          }
      }
      
  • 存在的问题

    • 由装饰者设计模式的弊端导致每个方法中都需要调用printLog方法

09_反射、注解、设计模式优化版

  • 开发步骤

    • 自定义注解@SystemLog
      • className
      • methodName
    • 定义一个UserDao接口,且在该接口使用注解@SystemLog
    • 动态代理
      • 获取UserDao接口中的方法对象
  • 代码实现

    • 自定义注解@SystemLog

      @Retention(RetentionPolicy.RUNTIME)
      public @interface SystemLog {
      
          String className();//记录类名
          String methodName();//记录方法名
      
      }
      
    • 定义一个UserDao接口,且在该接口使用注解@SystemLog

      • 设置@SystemLog中className属性、methodName属性
      public interface UserDao {
      
          @SystemLog(className = "com.qfedu.dao.UserDao" , methodName = "addUser")
          void addUser() throws Exception;
      
          void deleteUser() throws Exception;
      
          @SystemLog(className = "com.qfedu.dao.UserDao" , methodName = "updateUser")
          void updateUser() throws Exception;
      
      }
      
    • 动态代理

              UserDao userDao = new UserDaoImpl();
              UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
                      userDao.getClass().getClassLoader(),
                      userDao.getClass().getInterfaces(),
                      new InvocationHandler() {
                          @Override
                          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                              //获取到接口中方法对象 , 比如 : UserDao接口中addUser方法
                              //之前
                              //先获取实现子类的Class对象
                              //再获取到接口的Class对象
                              //再获取到接口中的方法对象
                              //现在
                              //再获取到接口的Class对象  -- userDao.getClass().getInterfaces(),
                              //再获取到接口中的方法对象  --  Method method
                              //method : 就是接口中的方法对象
                              Object returnValue = null;
                              if (null != method) {
                                  boolean present = method.isAnnotationPresent(SystemLog.class);
                                  if (present) {
                                      //如果有@SystemLog注解 , 执行原有功能 ,  打印日志
                                      returnValue = method.invoke(userDao, args);
                                      String currentTimeStr = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss")
                                              .format(new Date());
                                      SystemLog systemLog = method.getAnnotation(SystemLog.class);
                                      String className = systemLog.className();
                                      String methodName = systemLog.methodName();
                                      System.out.println(currentTimeStr + " --- " + className + "类中 ---" + methodName + "()方法 --- 运行了");
                                  } else {
                                      //如果没有@SystemLog注解, 执行原有功能, 不打印日志
                                      returnValue = method.invoke(userDao, args);
                                  }
                              }
      
                              return returnValue;
                          }
                      });  
              userDaoProxy.addUser();
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值