`

JDK5--Annotation学习:基础(二)

 
阅读更多

转载自:http://www.iteye.com/topic/1123823

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”。以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助。):

[1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081
[2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293
[3] 属性编辑器,即PropertyEditor-->Spring IoC:http://www.iteye.com/topic/1123628
[4] XML基础知识-->Spring配置:http://www.iteye.com/topic/1123630
[5] 注解-->Spring配置:http://www.iteye.com/topic/1123823
[6] 线程本地变更,即ThreadLocal-->Spring事务管理:http://www.iteye.com/topic/1123824
[7] 事务基础知识-->Spring事务管理:http://www.iteye.com/topic/1124043
[8] 国际化信息-->MVC:http://www.iteye.com/topic/1124044
[9] HTTP报文-->MVC:http://www.iteye.com/topic/1124408



有必要对JDK 5.0新增的注解(Annotation)技术进行简单的学习,因为Spring 支持@AspectJ,而@AspectJ本身就是基于JDK 5.0的注解技术。所以学习JDK 5.0的注解知识有助于我们更好地理解和掌握Spring的AOP技术。

了解注解

对于Java开发人员来说,在编写代码时,除了源程序以外,我们还会使用Javadoc标签对类、方法或成员变量进行注释,以便使用Javadoc工具生成和源代码配套的Javadoc文档。这些@param、@return等Javadoc标签就是注解标签,它们为第三方工具提供了描述程序代码的注释信息。使用过Xdoclet的朋友,对此将更有感触,像Struts、Hibernate都提供了Xdoclet标签,使用它们可以快速地生成对应程序代码的配置文件。

JDK5.0注解可以看成是Javadoc标签和Xdoclet标签的延伸和发展。在JDK5.0中,我们可以自定义这些标签,并通过Java语言的反射机制中获取类中标注的注解,完成特定的功能。
注解是代码的附属信息,它遵循一个基本原则:注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,而这正是Spring AOP对@AspectJ提供支持所采取的方法。

引用
很多东西的设计都必须遵循最基本的原则,为了防止机器人伤害人类,科幻作家阿西莫夫于1940年提出了“机器人三原则”:第一,机器人不能伤害人类;第二,机器人应遵守人类的命令,与第一条违背的命令除外;第三,机器人应能保护自己,与第一条违背的命令除外。这是给机器人赋予的伦理性纲领,机器人学术界一直将这三条原则作为机器人开发的准则。



一个简单的注解类

通常情况下,第三方工具不但负责处理特定的注解,本身还提供了这些注解的定义,所以我们通常仅需关注如何使用注解就可以了。但定义注解类本身并不困难,Java提供了定义注解的语法。下面,我们马上着手编写一个简单的注解类,如代码清单7-1所示:

代码清单7-1  NeedTest注解类

Java代码 复制代码 收藏代码

 

package com.baobaotao.aspectj.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) //①声明注解的保留期限
@Target(ElementType.METHOD)//②声明可以使用该注解的目标类型
public @interface NeedTest {//③定义注解
	boolean value() default true;//④声明注解成员
}



Java新语法规定使用@interface修饰符定义注解类,如③所示,一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅定义了一个成员,如④所示。成员的声明有以下几点限制:

  • 成员以无入参无抛出异常的方式声明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;
  • 可以通过default为成员指定一个默认值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,当然也可以不指定默认值;
  • 成员类型是受限的,合法的类型包括原始类型及其封装类、String、Class、enums、注解类型,以及上述类型的数组类型。如ForumService value()、List foo()是非法的。



在①和②处,我们所看到的注解是Java预定义的注解,称为元注解(Meta-Annotation),它们被Java编译器使用,会对注解类的行为产生影响。@Retention(RetentionPolicy. RUNTIME)表示NeedTest这个注解可以在运行期被JVM读取,注解的保留期限类型在java.lang.annotation.Retention类中定义,介绍如下:

  • SOURCE:注解信息仅保留在目标类代码的源码文件中,但对应的字节码文件将不再保留;
  • CLASS:注解信息将进入目标类代码的字节码文件中,但类加载器加载字节码文件时不会将注解加载到JVM中,也即运行期不能获取注解信息;
  • RUNTIME:注解信息在目标类加载到JVM后依然保留,在运行期可以通过反射机制读取类中注解信息。   

 Target(ElementType.METHOD)表示NeedTest这个注解只能应用到目标类的方法上,注解的应用目标在java.lang.annotation.ElementType类中定义:

  • TYPE:类、接口、注解类、Enum声明处,相应的注解称为类型注解;
  • FIELD:类成员变量或常量声明处,相应的注解称为域值注解;
  • METHOD:方法声明处,相应的注解称为方法注解;
  • PARAMETER:参数声明处,相应的注解称为参数注解;
  • CONSTRUCTOR:构造函数声明处,相应的注解称为构造函数注解;
  • LOCAL_VARIABLE:局部变量声明处,相应的注解称为局域变量注解;
  • ANNOTATION_TYPE:注解类声明处,相应的注解称为注解类注解,ElementType. TYPE包括ElementType.ANNOTATION_TYPE;
  • PACKAGE:包声明处,相应的注解称为包注解。



如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),如@NeedTest(true)。注解类拥有多个成员时,如果仅对value成员进行赋值则也可不使用赋值号,如果同时对多个成员进行赋值,则必须使用赋值号,如DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。注解类可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;此外,所有的注解类都隐式继承于java.lang.annotation.Annotation,但注解不允许显式继承于其他的接口。

我们希望使用NeedTest注解对业务类的方法进行标注,以便测试工具可以根据注解情况激活或关闭对业务类的测试。在编写好NeedTest注解类后,就可以在其他类中使用它了。

使用注解

我们在ForumService中使用NeedTest注解,标注业务方法是否需要测试,如代码清单7-2所示:

代码清单7-2  ForumService:使用注解

Java代码 复制代码 收藏代码
package com.baobaotao.aspectj.anno;
public class ForumService {
    @NeedTest(value=true) ①
	public void deleteForum(int forumId){
		System.out.println("删除论坛模块:"+forumId);
	}
    @NeedTest(value=false) ②
    public void deleteTopic(int postId){
		System.out.println("删除论坛主题:"+postId);
	}	
}



如果注解类和目标类不在同一个包中,需要通过import引用的注解类。在①和②处,我们使用NeedTest分别对deleteForum()和deleteTopic()方法进行标注。在标注注解时,可以通过以下格式对注解成员进行赋值:

引用
@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)



如果成员是数组类型,可以通过{}进行赋值,如boolean数组的成员可以设置为{true,false,true}。下面是几个注解标注的例子:

示例1,多成员的注解:

Java代码 复制代码 收藏代码
@AnnoExample(id= 2868724, synopsis = "Enable time-travel",
engineer = "Mr. Peabody",date = "4/1/2007")



示例2,一个成员的注解,成员名为value。可以省略成员名和赋值符号:

Java代码 复制代码 收藏代码
@Copyright("2011 bookegou.com All Right Reserved")



示例3,无成员的注解:

Java代码 复制代码 收藏代码
@Override



示例4,成员为字符串数组的注解:

Java代码 复制代码 收藏代码
@SuppressWarnings(value={"unchecked","fallthrough"})



示例5,成员为注解数组类型的注解:

Java代码 复制代码 收藏代码
@Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),      
           @Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",              
                    comment="This method needs an @Override annotation")})



@Reviews注解拥有一个@Review注解数组类型的成员,@Review注解类型有三个成员,其中reviewer、comment都是String类型,但comment有默认值,grade是枚举类型的成员。

由于NeedTest注解的保留限期是RetentionPolicy.RUNTIME类型,因此当ForumService被加载到JVM时,仍就可通过反射机制访问到ForumService各方法的注解信息。

访问注解

前面提到过,注解不会直接影响程序的运行,但是第三方程序或工具可以利用代码中的注解完成特殊的任务,间接控制程序的运行。对于RetentionPolicy.RUNTIME保留期限的注解,我们可以通过反射机制访问类中的注解。

在JDK5.0里,Package、Class、Constructor、Method以及Field等反射对象都新增了访问注解信息的方法:<T extends Annotation>T getAnnotation(Class<T> annotationClass),该方法支持通过泛型直接返回注解对象。

下面,我们就通过反射来访问注解,得出ForumService 类中通过@NeedTest注解所承载的测试需求,如代码清单7-3所示:

代码清单7-3  TestTool:访问代码中的注解

Java代码 复制代码 收藏代码

  

package com.baobaotao.aspectj.anno;
import java.lang.reflect.Method;
public class TestTool {
	public static void main(String[] args) {
                
               //①得到ForumService对应的Class对象
		Class clazz = ForumService.class; 

                //②得到ForumSerivce对应的Method数组
		Method[] methods = clazz.getDeclaredMethods(); 

		System.out.println(methods.length);
		for (Method method : methods) {

                        //③获取方法上所标注的注解对象
			NeedTest nt = method.getAnnotation(NeedTest. class);
			if (nt != null) {
				if (nt.value()) {
					System.out.println(method.getName() + "()需要测试");
				} else {
					System.out.println(method.getName() + "()不需要测试");
				}
			}
		}
	}
}



在③处,通过方法的反射对象,我们获取了方法上所标注的NeedTest注解对象,接着就可以访问注解对象的成员,从而得到ForumService类方法的测试需求。运行以上代码,输出以下的信息:

引用
deleteForum()需要测试
deleteTopic()不需要测试
分享到:
评论

相关推荐

    Annotation--学习:JDK内建Annotation

    在本篇中,我们将深入探讨JDK内置的Annotation,了解它们的用途、工作原理以及如何在实际开发中应用。 1. **注解的基本概念** 注解是一种特殊类型的声明,可以附加到类、接口、字段、方法、构造器等程序元素上。...

    jdk-8u20-docs-all.zip

    本压缩包"jdk-8u20-docs-all.zip"提供了Java SDK 8更新20版本的完整文档,对于开发者来说,是一份极其重要的参考资料。 在Java编程中,了解各个类的名称和用法是至关重要的。这个文档集合详细地介绍了Java平台的...

    JDK5.0 Java Annotation 介绍(ppt)

    Java Annotation 是 JDK5.0 引入的一种元数据机制,它允许程序员在代码中嵌入额外的信息,这些信息可以被编译器、构建工具或运行时系统用来执行特定的任务。Annotation 提供了一种安全、灵活的方式来描述代码的属性...

    Java 5 annotation 学习笔记

    Java 5引入的注解(Annotation)是一种元数据,它提供了在代码中嵌入信息的方式,这些信息可以被编译器、JVM或其他工具在编译时或运行时使用。注解可以用来简化代码,提高可维护性,并帮助工具进行静态分析。 1. ...

    JDK11-annotation-processor-reproducer:Java 11问题的小型复制器

    运行应用程序的构建: mvn clean install编译不会通过以下问题: [INFO] ------------------------------------------------------------------------[INFO] Reactor Summary for annotation-processor 1.0-...

    Java-Annotation手册.docx

    5. Annotation 处理工具: - `apt` 工具:在 JDK/bin 目录下,它可以扫描源代码中的 Annotation 并调用用户定义的 Annotation 处理器,执行特定任务,如验证、代码生成等。 总的来说,Java Annotation 提供了一种...

    离线JDK9中文版 | API_jdk-9.CHM

    Java开发工具包(Java Development Kit,简称JDK)是Java编程语言的标准开发环境,它包含了编译、运行Java程序所需的各种工具和库。这个离线JDK9中文版的API文档,即`API_jdk-9.CHM`,是开发者在没有网络连接时查阅...

    javax.annotation-api-1.3.2

    JDK9及以上版本没有javax.annotation-api-***.jar包 ,无法使用注解:@Resource JDK新特性,高版本JDK没有自带的javax(java扩展包)了。或者是使用的JDK不完整。 下载javax.annotation.jar包,导入到lib文件夹下,...

    JDK5.0-Java Annotation 介绍

    Java Annotation(注解)是自JDK 5.0开始引入的一种元数据,它提供了一种安全、非侵入式的方式来向编译器、虚拟机或者其他的工具提供关于代码的信息。这种信息可以用来进行编译时检查、运行时处理、代码生成等。注解...

    良葛格Java JDK 5.0学习笔记

    这份《良葛格Java JDK 5.0学习笔记》全面覆盖了Java编程的基础到进阶知识,特别关注了JDK 5.0的新特性,对于想要掌握Java编程的人来说是一份非常实用的学习资料。通过深入学习和实践,读者将能够熟练掌握Java编程,...

    jdk-9.0.1_doc-all 最新版

    The Java Development Kit (JDK) APIs are specific to the JDK and will not necessarily be available in all implementations of the Java SE Platform. These APIs are in modules whose names start with jdk....

    jdk-11.0.9_doc-all.zip

    5. **枚举、注解类型和常量**:除了类和接口,文档还涵盖了枚举类型、注解(Annotation)和常量的定义。 6. **附录和索引**:在文档的最后,通常会有类索引、模块索引、关键字索引等,方便开发者快速查找所需信息。...

    java基础核心总结归纳---参考手册--心得手册-学习资料-总结经验

    - JDK包含Java运行环境、工具和核心类库,是开发Java应用的必备工具。 - JRE是Java运行环境,是运行Java程序所必需的。 3. Java 基本语法 - 数据类型:包括整数型(byte, short, int, long),浮点型(float, ...

    511.509.JAVA基础教程_枚举类与注解-jdk8新特性:类型注解(511).rar

    通过学习枚举类、注解和类型注解,开发者能够编写出更加优雅、可维护的Java代码。枚举类提供了更安全的常量管理,注解则增强了代码的元数据功能,而类型注解则进一步提升了代码的静态分析和错误预防能力。对于Java...

    JDK-1.8-sourcecode:JDK 1.8源代码

    JDK 1.8源代码涵盖了Java语言的基础组件,包括语法解析、类型检查、字节码生成等。通过对`javac`编译器的源代码学习,我们可以了解到如何将Java源代码转换为可执行的字节码,这对于理解Java的编译过程至关重要。 2...

    gradle-errorprone-plugin:Gradle插件可使用易于出错的Java编译器

    该插件创建一个名为errorprone的配置,并为每个源集配置&lt;sourceSet&gt;AnnotationProcessor配置以扩展它。 这允许从单个位置配置容易出错的依赖项。 需要在此配置中添加容易出错的依赖关系: repositories { maven...

    collectionJava源码-jdk-source-code-reading:JDK源代码阅读

    collection Java 源码 概述 主要分析 JDK8 源码。 基础 java-io java-nio java-reflect java-collection java-annotation java-net java-jdbc java-concurrent java-jvm java8

    maven-annotation-plugin:一个Maven插件,可在编译时处理来自jdk6及更高版本的注释

    一个Maven插件,用于处理jdk8及更高版本的编译时注释。 该插件有助于从Maven使用JDK8提供的集成在Java编译器中的新注释处理 该插件是Maven apt插件的“ alter ego” 文献资料 相关插件 插入 信息 Jboss的eclipse...

    jdk-1_5_0_11-windows-i586-p

    标题“jdk-1_5_0_11-windows-i586-p”指的是Java Development Kit(JDK)的第1.5.0_11版本,特别为Windows i586(即32位)平台设计。这个版本的JDK是Java编程语言的重要工具集,它包含了编译器、调试器、文档生成器...

    java注解源码-java-custom-annotation:教程的源代码如何创建自定义Java批注

    Java注解是Java编程语言中的一个重要特性,它允许程序员在代码中嵌入元...对于深入学习,建议阅读Java官方文档以及相关的开源项目,如本教程提供的`java-custom-annotation-master`,以获得更丰富的实践经验和理解。

Global site tag (gtag.js) - Google Analytics