java注解是怎么实现的,java注解编程

  java注解是怎么实现的,java注解编程

  背景为什么要再次梳理java注释?很明显,因为它很重要。也为研究各种开源框架做了铺垫。只有搞清楚Java注释的相关原理,才能理解大多数框架的底层设计。

  原点注记也称为元数据,是1.5版中引入的一项功能。它用于标记和解释代码,可以注释包、类、接口、字段、方法参数、局部变量等。它不包含任何业务逻辑。

  一般来说,有三种注释:

  JDK自己的相关标注、自定义标注、第三方标注(比如相关框架中的标注)有三个步骤:定义、配置、解析。

  定义:定义标签配置:将标签键入需要使用的代码中;解析:在编译器或运行时检测标签,并对元注释执行特殊操作。什么是元注释?注释的作用是注释其他的注释。有五种注释:

  @Retention:指定其修改的注释的保留策略@Document:该注释为标记注释,用于表示注释将被记录@Target:用于限制注释的应用范围@Inherited:该注释使父类的注释能够被其子类继承@Repeatable:该注释是Java8中的新注释,用于开发重复注释@Retention注释用于指定修改后的注释可以保留多长时间,即指定JVM策略。

  目前,有三种策略

  JVM可以在保留的运行时获得注释信息(反射)。运行时,这是最长的注释持续时间。@Document annotation @ Document annotation用于指定可以通过javadoc工具将修饰的注释提取到@ Document中。如果在定义注解类时用@Document注解来修饰它,那么用注解修饰的程序元素的所有API文档都将包含注解描述。

  @ Target annotation @ Target annotation用于限制注释的范围,即指定修饰的注释可以用于哪些程序单元。标注方法如下:@Target({应用类型1,应用类型2,}) [@ target (elementtype.field)]

  枚举值介绍如下:

  @ Inherited annotation @ Inherited annotation指定批注是继承的。如果注释是用@Inherited修饰的,那么当类使用注释时,它的子类会自动被修饰。

  按照上面的三步流程,我们举一个写代码的例子来说明:

  (1)定义注释

  @Target(ElementType。类型)

  @保留(RetentionPolicy。运行时间)

  @继承

  public @interface继承扩展{

  字符串注释();

  int order()默认为1;

  }(2)配置:标记类。

  @ inherited extend(comment= comment inheritance ,order=2)

  公共基类{

  }(3)分析:获取评论,分析测试。

  公共类InheritedDemo扩展基{

  公共静态void main(String[] args) {

  //从此类获取父类的注释信息

  inherited extend extend=inherited demo . class . get annotation(inherited extend . class);

  //输出InheritedExtend批注成员信息

  system . out . println(extend . comment(): extend . order());

  //打印出InheritedDemo类是否有@InheritedExtend修饰。

  system . out . println(inherited demo . class . isanotationpresent(inherited extend . class));

  }

  }结果输出:

  评论继承性:2 true的上述结果很好地说明了这个评论的继承性。

  @ Repeatable comment @ Repeatable comment是Java8中的新注释,用于开发重复性注释。在Java8之前,同一个程序元素之前只能使用一个同类型的注释。如果需要在同一个元素之前使用多个同类型的标注,就必须通过标注容器来实现。从Java8开始,允许使用多个同类型的注释来修饰同一个元素,前提是同类型的注释是可重复的,即在定义注释时要用@Repeatable元注释来修饰。

  (1)定义注释

  @Target(ElementType。类型)

  @保留(RetentionPolicy。运行时间)

  @ Repeatable(annol contents . class)

  public @ interface RepeatableAnnol {

  String()默认为“老猫”;

  int age();

  }

  //注释为容器,

  @Target(ElementType。类型)

  @保留(RetentionPolicy。运行时间)

  @界面公告内容{

  //定义value成员变量,该变量可以接受多个@ Repeatableinnol批注。

  repeatable annol[]value();

  }(2)注解使用以及解析

  @RepeatableAnnol(name=张三,年龄=12岁)

  @RepeatableAnnol(年龄=23岁)

  公共类RepeatableAnnolDemo {

  公共静态void main(String[] args) {

  RepeatableAnnol[]repeatableAnnols=repeatableannoldemo。班级。getdeclaredannotationsbytype(RepeatableAnnol。类);

  for(RepeatableAnnol RepeatableAnnol:repeatableAnnols){

  系统。出去。println(可重复的annol。name()-可重复的annol。年龄());

  }

  annol contents annol contents=repeatableannoldemo。班级。getdeclaredannotation(annol内容。类);

  系统。出去。println(annol内容);

  }

  }结果输出:

  张三- 12

  老猫- 23

  @ com。卡帕头爸爸。注释。可重复。annol内容(value={ @ com。卡帕头爸爸。注释。可重复。可重复的annol(名称=张三,年龄=12),@ com。卡帕头爸爸。注释。可重复。可重复的annol(名称=老猫,年龄=23)})自定义注解实战应用利用注解解析实现系统日志记录,主要用于记录相关的日志到数据库,当然,老猫这里的演示只会到日志打印层面,至于数据库落库存储有兴趣的小伙伴可以进行扩展。

  以下是专家依赖:

  属国

  属国

  groupId组织。spring框架。boot/groupId

  项目的名称弹簧启动启动器/artifactId

  /依赖关系

  属国

  groupId组织。spring框架。boot/groupId

  工件id spring-boot-starter-web/工件id

  /依赖关系

  属国

  groupId组织。spring框架。boot/groupId

  artifactId spring-boot-starter-AOP/artifactId

  /依赖关系

  属国

  groupId com.alibaba /groupId

  artifactId fastjson /artifactId

  版本1 .2 .79/版本

  /依赖关系

  /依赖关系注解的定义如下:

  @Target(ElementType .方法)

  @保留(保留政策.运行时间)

  @已记录

  公共@接口操作日志{

  字符串desc()默认为"";

  }这个地方只是定义了一个字段,当然大家也可以进行拓展。

  接下来,咱们以这个注解作为切点编写相关的切面程序。具体代码如下:

  @Aspect

  @组件

  @Order(0)

  公共类操作设备{

  @ Pointcut( @ annotation(com。卡帕头爸爸。注释。操作日志)’)

  公共void recordLog(){

  }

  @Around(recordLog())

  公共对象recordLogOne(过程连接点连接点)抛出可投掷的

  System.out.println(进来了);

  方法签名方法签名=(方法签名)连接点。获取签名();

  方法方法=方法签名。get方法();

  操作日志操作日志=方法签名。获取方法().获取注释(操作日志。类);

  string spELString=操作日志。desc();

  //创建解析器

  SpelExpressionParser parser=new SpelExpressionParser();

  //获取表达式

  表达式表达式=解析器。解析表达式(spELString);

  //设置解析上下文(有哪些占位符,以及每种占位符的值)

  EvaluationContext context=new standardyevaluationcontext();

  //获取参数值

  object[]args=连接点。get args();

  //获取运行时参数的名称

  DefaultParameterNameDiscoverer discoverer=new DefaultParameterNameDiscoverer();

  string[]参数名称=discoverer。获取参数名(方法);

  for(int I=0;我参数名字。长度;i ) {

  语境。set变量(参数名[I],args[I]);

  }

  //解析,获取替换后的结果

  字符串结果=表达式。getvalue(上下文)。toString();

  System.out.println(结果);

  返回连接点。proceed();

  }

  }关于切面这块不多做赘述,非本篇文章的重点。

  接下来就可以在我们的代码层面使用相关的注解了,具体如下:

  @服务

  公共类对象实现用户服务{

  @OperateLog(desc=#user.desc )

  公共void saveUser(用户用户){

  System.out.println(测试注解.);

  }

  }关于控制器层面就省略了,都是比较简单的。

  通过上述切面以及注解解析,我们可以获取每次传参的参数内容,并且将相关的日志进行记录下来,当然这里面涉及到了表达式语言表达式注入,相关的知识点,小伙伴们可以自行学习。

  最终启动服务,并且请求之后具体的日志如下。

  进来了

  这是测试

  测试注解.

  {age:12, desc :这是一个测试, id:1, name :张三, operator: operator}至此,关于Java注释的回顾性学习已经结束,接下来我们再来看一些底层代码可能就容易多了。

  版权归作者所有:原创作品来自博主小二上九8,转载请联系作者取得转载授权,否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: