摘要:元注解元注解用于注解其他注解的。该注解表明子类是有继承了父类的注解。在注解中,需要使用四种元注解来声明注解的作用范围生命周期继承,是否生成文档等。另外在注解中也可以有自己的成员变量,如果一个注解没有成员变量则称为标记注解。
在使用SpringBoot作为Web敏捷开发的框架之后,SpringBoot除了自动装配配置的便捷之外,在很多时候需要基于注解来开发。注解不仅增加了代码的可读性,还增加了开发的速度。这篇文章主要讲述Java 注解。
元注解
元注解用于注解其他注解的。Java 5.0定义了4个标准的元注解,如下:
@Target @Retention @Documented Inherited
现在来说说这四个元注解有什么作用
@Target
@Target注解用于声明注解的作用范围,例如作用范围为类、接口、方法等。它的取值以及值所对应的范围如下:
**CONSTRUCTOR:用于描述构造器
FIELD:用于描述域
LOCAL_VARIABLE:用于描述局部变量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述参数
TYPE:用于描述类、接口(包括注解类型) 或enum声明**
@Retention
该注解声明了注解的生命周期,即注解在什么范围内有效。
*SOURCE:在源文件中有效
CLASS:在class文件中有效
RUNTIME:在运行时有效(即运行时保留)
大多数注解都为RUNTIME*
@Documented
是一个标记注解,有该注解的注解会在生成 java 文档中保留。
@Inherited
该注解表明子类是有继承了父类的注解。比如一个注解被该元注解修饰,并且该注解的作用在父类上,那么子类有持有该注解。如果注解没有被该元注解修饰,则子类不持有父类的注解。
自定义注解
在Java开发者,JDK自带了一些注解,在第三方框架Spring 带了大量的注解,这些注解称为第三方注解。在很多实际开发过程中,我们需要定义自己的注解。那么现在以案例的方式来讲解自定义注解。
在注解中,需要使用四种元注解来声明注解的作用范围、生命周期、继承,是否生成文档等。另外在注解中也可以有自己的成员变量,如果一个注解没有成员变量则称为标记注解。注解的成员变量,只支持原始类型、Class、Enumeration、Annoation。
现在定义一个@Writer注解,该注解被Retention、Documented、Inherited、Target修饰,表明该注解的作用范围为类、接口和方法,生命周期为运行时、该注解生成文档,并且子类可继承该注解。该注解有2个成员变量,一个为name一个为 age,代码如下:
@Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Target({ElementType.TYPE,ElementType.METHOD}) public @interface Writer { String name(); int age(); }
那么有了该注解,怎么用呢?
该注解的作用范围为类、方法,写一个WriterTest,代码如下:
@Writer(name = "forezp", age = 12) public class WriterTest { @Writer(name = "miya", age = 10) public void writeBlog() { System.out.println("writing blog"); } }
该类有了这个注解有何用?
一般来说,用该类修饰的类,需要通过反射来做一下逻辑的开发的工作,可广泛用于AOP、程序的配置等。现在写一个方法通过反射来解析该注解:
public static void main(String[] args) throws ClassNotFoundException { Class c = Class.forName("com.forezp.annotation.WriterTest"); if (c.isAnnotationPresent(Writer.class)) { Writer w = (Writer) c.getAnnotation(Writer.class); System.out.println("name:" + w.name() + " age:" + w.age()); } Method[] methods = c.getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Writer.class)) { Writer w = method.getAnnotation(Writer.class); System.out.println("name:" + w.name() + " age:" + w.age()); } } }
这些代码基本为反射的内容,因为反射在另一篇文章已经详细讲述过,不再重复,运行该Main方法,控制台打印出如下内容:
*name:forezp age:12
name:miya age:10*
案例实战
有了上述的讲解,你可能对注解有所了解,但是对注解的具体应用并不是很深刻。现在以一个案例来详细讲述。
大家都对ORM框架Mybitis都非常的熟悉,在这个框架中用了大量的注解。现在模仿这个框架,通过自定义注解,来解析sql 的查询语句。实现过程大概如下:
*定义@Table @Colum注解
定义一个实体User,定义一些基本的字段,并用注解修饰
用User类new对象,给对象的某些字段赋值
通过反射和注解来生成sql 的查询语句*
首先定义个一个Table注解,它的作用范围为类,代码如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Inherited public @interface Table { String value() default ""; }
定义一个Column注解,作用范围为字段,代码如下:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Column { String value(); }
定义一个User类,在该类的加上@Table注解,在具体的字段上 @Column注解,代码如下:
@Table("user") public class User { @Column("id") private int id; @Column("name") private String name; @Column("age") private int age; @Column("address") private String address; ..//省略getter setter }
写一个生成sql语句的类,它是通过反射来获取表名、字段名,加上判断实体对象的字段值来生成 查询的 sql 语句的。代码如下:
public class GenUserSql { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { User u1 = new User(); User u2 = new User(); u1.setId(1); u2.setName("forezp"); genSql(u2); genSql(u1); } private static void genSql(User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class c = user.getClass(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("select * from "); if (c.isAnnotationPresent(Table.class)) { Table table = (Table) c.getAnnotation(Table.class); String tableName = table.value(); stringBuilder.append(tableName).append(" where 1=1 and "); } Field[] fields = c.getDeclaredFields(); for (Field field : fields) { String columnName; if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); columnName = column.value(); } else { continue; } String fieldName = field.getName(); String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Method method = c.getMethod(getMethodName); Object fieldValue = method.invoke(user); if (fieldValue == null || ((fieldValue instanceof Integer) && (Integer) fieldValue == 0)) { continue; } if (fieldValue instanceof Integer) { stringBuilder.append(columnName + "=" + fieldValue); } if (fieldValue instanceof String) { stringBuilder.append(columnName + "=" + """ + fieldValue + """); } } System.out.println(stringBuilder.toString()); } }
运行程序,控制台打印如下:
*>
select * from user where 1=1 and name="forezp"
select from user where 1=1 and id=1
欢迎加入学习交流群569772982,大家一起学习交流。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/70499.html
摘要:注解概念注解也被成为元数据为我们在代码中添加信息提供了一种形式化的方式,使我们可以在稍后的某个时刻更容易的使用这些数据。 注解 概念 注解(也被成为元数据)为我们在代码中添加信息提供了一种形式化的方式,使我们可以在稍后的某个时刻更容易的使用这些数据。 注解是 Java 5 所引入的众多语言变化之一: 注解使得我们可以以编译器验证的格式存储程序的额外信息 注解可以生成描述符文件,甚至是...
摘要:核心注解讲解最大的特点是无需配置文件,能自动扫描包路径装载并注入对象,并能做到根据下的包自动配置。所以最核心的个注解就是这是添加的一个注解,用来代替配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。 最近面试一些 Java 开发者,他们其中有些在公司实际用过 Spring Boot, 有些是自己兴趣爱好在业余自己学习过。然而,当我问他们 Spring Boo...
摘要:使用会涉及到各种各样的配置,如开发测试线上就至少套配置信息了。本章内容基于进行详解。添加测试类运行单元测试,程序输出根据以上参数动态调整,发现参数会被正确被覆盖。了解了各种配置的加载顺序,如果配置被覆盖了我们就知道是什么问题了。 使用 Spring Boot 会涉及到各种各样的配置,如开发、测试、线上就至少 3 套配置信息了。Spring Boot 可以轻松的帮助我们使用相同的代码就能...
摘要:从使用到原理学习线程池关于线程池的使用,及原理分析分析角度新颖面向切面编程的基本用法基于注解的实现在软件开发中,分散于应用中多出的功能被称为横切关注点如事务安全缓存等。 Java 程序媛手把手教你设计模式中的撩妹神技 -- 上篇 遇一人白首,择一城终老,是多么美好的人生境界,她和他历经风雨慢慢变老,回首走过的点点滴滴,依然清楚的记得当初爱情萌芽的模样…… Java 进阶面试问题列表 -...
阅读 1849·2021-11-24 09:39
阅读 2055·2021-09-22 15:50
阅读 1739·2021-09-22 14:57
阅读 679·2021-07-28 00:13
阅读 1020·2019-08-30 15:54
阅读 2341·2019-08-30 15:52
阅读 2598·2019-08-30 13:07
阅读 3739·2019-08-30 11:27