1. 前言
自JDK1.5以后,推出了注解新特性。注解的推出其实最主要的目的是为了让广大的用户认知EJB3.0,因为EJB2.X广受大多数开发者的诟骂和质疑。为了减少配置、让注解替代配置。有了注解,我们以前看似一般的、普通的JavaBean就有了活力,有了内涵,有了新的契机。配合Sun的JPA规范,EJB3.X又再次在企业级开发中大放异彩,让很多开发者赞不绝口。也许是无心插柳,这种“零配置”思维也影响着Java其他的开源项目——像Struts、Spring、Hibernate(也就是咱们耳熟能详的SSH)不都是具有“零配置”支持嘛!Java现在也是往动态、敏捷的方向发展着。有可能将来配置文件越来越少、规范、约定、注解代替了繁琐的配置信息。而XML估计会回归原始的使命——数据传输与数据交换。
2. 自定义注解
至于已有的注解,比如:JPA、EJB、Spring零配置等等怎么使用相信各位读者都能掌握,这里主要是说如何自定义自己的注解,自己使用自定义的注解。
我们先用一个简单的例子来看
package annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 注解
*
* @author Administrator
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String isAop() default "false";
}
|
用关键字@interface定义一个注解标记,使用@interface关键字实际上的意思就是该接口继承自java.lang.annotation.Annotation接口。
String isAop() default "false";
|
这句话代表的意思就是在Test注解中可以含有属性名为isAop,此属性的类型是字符串类型。客户端使用的时候可以根据需要自己指定相关的属性值。如果客户端不指定值,默认值是false
@Retention(RetentionPolicy.RUNTIME)
|
这句话代表着将使用该注解类的信息值保持到真正的客户端运行时环境。
下面我们就来看看客户端的使用
package use;
import annotation.Test;
import annotation.TestImpl.TestProcess;
@Test(isAop = "true")
public class UseTest {
/**
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args)
throws ClassNotFoundException {
TestProcess.process("use.UseTest");
}
}
|
在客户端调用中在类UseTest上使用了@Test(isAop = "true")注解。仅仅定义了注解就像《三国杀》里,刘备是主公,他有“激将”的主公计,下了个命令:“蜀将何在?”,刘备的这句话太抽象了,蜀将相当于一个注解。在场的所有蜀将就像加了此注解的类,都会受到这句话的影响。具体替不替刘备出杀,~~~~个人表现不同(得先看看自己的身份啊)反贼的表现是:“这个真没有”;忠臣的表现是,先看看手上有杀吗?有,出击吧!没有就说:“这个……真没有!”;内奸的反应是:“唉,先保命还是装一装忠臣?比较纠结!”。这里的身份就好像是注解的属性的不同值。具体的处理就相当于针对注解的处理实现类。注解的具体实现类就是处理注解的业务逻辑,它需要Java的反射机制来处理客户目标类的具体注解,我们就来看看这个注解处理实现类。
package annotation.TestImpl;
import java.lang.annotation.Annotation;
public class TestProcess {
public static void process(String str)
throws ClassNotFoundException {
Class clazz = Class.forName(str);
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
|
以上的处理逻辑很简单,就是根据一个字符串类名找到类。获得类的所有注解,所有注解是一个对象数组。遍历注解数组,输出相关注解信息。运行以上的程序结果如下
@annotation.Test(isAop=true)
|
如果我们使用注解的客户端代码替换一下
@Test
public class UseTest {
……………………
}
|
对于注解的isAop并不特别指定。运行效果如下
@annotation.Test(isAop=false)
|
可以看到使用的是默认值false。如果注解中Annotation并没有指定默认值,而在客户端使用中也没指定值,那么不会通过编译。
@Retention(RetentionPolicy.XXXXXX)上面说到了是保留注解的有效期。
//会将注解保留到编译后的class中,加载类的时候不生效
@Retention(RetentionPolicy.CLASS)
//仅仅在代码保留,编译后的class不会保留
@Retention(RetentionPolicy.SOURCE)
//在编译后的class会有,通过反射也会获得注解信息
@Retention(RetentionPolicy.RUNTIME)
|
比如Override注解的源码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
|
因为复写在使用者使用的时候就可以看出来,所以没必要保留到运行期。
比如SuppressWarnings注解的源码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
|
以上的不提示警告的注解也是在编译一个类前检查即可。
以上还使用了@Target注解,它代表着注解的修饰范围,类型是java.lang.annotation.ElementType枚举类型。
public enum ElementType {
TYPE,//可以修饰类、接口、枚举、注解
FIELD,//可以修饰成员变量
METHOD,//可以修饰方法
PARAMETER,//可以修饰参数
CONSTRUCTOR,//可以修饰构造方法
LOCAL_VARIABLE,//可以修饰局部变量
ANNOTATION_TYPE,// 可以修饰Annotation
PACKAGE//可以修饰包
}
|
看Deprecated源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}
|
Deprecated代表已过时的意思,这是一个保持到运行期的注解,在运行期可以通过反射获取此注解。这里还使用了@Documented这个元注解。它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。
还有一个注解就是Inherited,如果使用了该标记,那么使用该注解的子类也会继承该注解的特性。
3. 实例
很多人有疑问,你说这些有什么用?对于开发有什么促进吗?EJB注解、JPA注解我们会使用完成业务不就得了。下面再来看一个程式例子
注解Pojo
package annotation;
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.TYPE)
public @interface Pojo {
String table();
}
|
注解Colum
package annotation;
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.FIELD)
public @interface Colum {
String columName();
boolean isNULL() default true;
String Type() default "";
}
|
处理注解的逻辑实现类
package annotation.TestImpl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import annotation.Colum;
import annotation.Pojo;
public class MyJPAProcess {
public static void process(Object object)
throws ClassNotFoundException {
// 所有注解
Annotation[] annotationsClass = object.getClass().getAnnotations();
Field[] fields = object.getClass().getDeclaredFields();
// 遍历注解元素
for (Annotation annotation : annotationsClass) {
if (annotation instanceof Pojo) {
System.out.println("--------处理POJO实体--------");
Pojo pojo = (Pojo) annotation;
System.out.println("存储表名:" + pojo.table());
}
}
for (Field field : fields) {
//field.setAccessible(true);
Annotation[] annotationsMethos = field.getAnnotations();
// 遍历注解元素
for (Annotation annotation : annotationsMethos) {
if (annotation instanceof Colum) {
System.out.println("--------处理Colum字段--------");
Colum colum = (Colum) annotation;
System.out.println("字段名:" + colum.columName());
System.out.println("字段类型:" + colum.Type());
System.out.println("是否能为空:" + colum.isNULL());
}
}
}
}
}
|
以上是定义了简单的2个注解Pojo和Colum。之后为这2个注解提供了逻辑处理。下面我们来看看客户端是怎么使用的吧。
一般的实体类
package use;
import annotation.Colum;
import annotation.Pojo;
@Pojo(table = "person")
public class PersionPOJO {
public PersionPOJO() {
super();
}
@Colum(columName = "id", isNULL = false, Type = "varchar")
private String id;
@Colum(columName = "name", isNULL = false, Type = "varchar")
private String name;
@Colum(columName = "age", isNULL = true, Type = "int")
private int age;
//省略set/get
}
|
这是一个普通的实体对象+自定义的注解。针对于这个POJO我们再定义一个DAO类操作这个POJO类。
package use;
import annotation.TestImpl.MyJPAProcess;
public class PersionDAO {
public void save(PersionPOJO persionPOJO)
throws ClassNotFoundException {
MyJPAProcess.process(persionPOJO);
}
public static void main(String[] args)
throws ClassNotFoundException {
PersionDAO persionDAO = new PersionDAO();
PersionPOJO persionPOJO = new PersionPOJO();
persionDAO.save(persionPOJO);
}
}
|
上面程序就定义了一个保存方法,测试一下,调用这个save方法。控制台输出如下信息。
--------处理POJO实体--------
存储表名:person
--------处理Colum字段--------
字段名:id
字段类型:varchar
是否能为空:false
--------处理Colum字段--------
字段名:name
字段类型:varchar
是否能为空:false
--------处理Colum字段--------
字段名:age
字段类型:int
是否能为空:true
|
DAO中调用了注解逻辑实现类的方法。这个时候我们稍微修改一下注解逻辑实现类的方法,配合一个ORM中间件,就可以将数据保存到数据库了。
4. 总结
其实自定义注解一般是公司或者团队觉得一些原有的配置比较麻烦,加上注解是为了减少配置。还有一个目的:自己开发框架,让自己的团队更敏捷、更快速的相应纷繁错杂的客户需求。其实还有一个目的:就是制定规范,JPA是规范、EJB是规范……至于底层对于这些注解规范的实现则因不同的容器决定的。所谓容器就是JBoss或者Weblogic这种JavaEE容器的自己的jar包,像Java SDK也是提出了相应的规范,不同的组织对这个规范的实现也是仁者见仁智者见智,像上面提出的JDK内的注解就是提出了规范,我自己sun有一套实现机制,其他的组织用我sun的JDK实现不爽也可以自行实现这套注解机制。这样通过反射机制获取本应该在配置文件中配置的一些信息。减少了冗余的配置文件。至于效率嘛~~~有人说反射机制比解析配置慢、有人说配置文件要是过长会比反射慢很多。这个笔者觉得仁者见智者见智,没有绝对的答案,到底使用哪个?还是得因环境而异。
分享到:
相关推荐
Java基础复习笔记12Java自定义注解Annotation的使用
java自定义 注解 annotation、标签库tag、监听listener、junit简单测试代码
java 元注解+拦截器实现自定义注解 @CmwAutoWired:自定义依赖注入 注意:注入的接口和实现类需要在同一包名下,注解的是类则无限制 @FieldAnnotation:自定义属性注解 @MethodAnnotation:自定义方法注解 @...
本文全面讲述了Java注解Annotation与Java自定义注解及相关内容,大家可以认真看看
注解Annotation实现原理与自定义注解例子 每当你创建描述符性质的类或者接口时,一旦其中包含重复性的工 作,就可以考虑使用注解来简化与自动化该过程。 Java提供了四种元注解,专门负责新注解的创建工作
学习java自定义注解的小例子,处理运行时注解方法,可以结合博客学习,博客地址: http://blog.csdn.net/liuyonglei1314/article/details/59494503
我们在项目开发过程中,可能会对一些公用方法抽成工具类进行使用。如果我们把这些方法再抽成注解的形式,在一些业务情况下是否更灵活一些呢? 示例是纯净的,只引入了需要的架包,启动后直接访问:ip:port/user/test ...
要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法
初学者可以通过以上的说明制作简单的annotation程序,但是对于一些高级的annotation应用(例如使用自定义annotation生成javabean映射xml文件)还需要进一步的研究和探讨。涉及到深入annotation的内容,作者将在后文...
《利用反射技术处理自定义注解》的设计与实现 AnnotationPrj,具体分annotation、deal、domain、test、util四个层来实现
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。注解...
@Target:用于描述注解的使用范围,如果自定义注解不存在@Target,则表示该注解可以使用在任何程序元素之上。接收参数ElementType,其值如下: /**接口、类、枚举、注解**/ ElementType.TYPE /**字段、枚举的常量**/...
自定义Result,自定义Annotation的实例
在UI自动化测试中,相信很多人都喜欢用所谓的PO模式,其中的P,也是page的意思,于是乎,在脚本里,或者在其它的page里,会要new很多的page对象,这样很麻烦,前面我们也讲到了注解的使用,很方便,那么我们可不可以...
前言 公司前端项目用的是vue,后端...在使用自定义注解之前,我们先来了解Java为我们提供的元注解和相关定义注解的语法。 一、了解Java注解语法 1.元注解(meta-annotation) 元注解的作用就是负责注解其他注解,在java.
下面小编就为大家带来一篇浅谈Java中注解Annotation的定义、使用、解析。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
Annotation使用手册,提供JAVA 1.5+版本关于Annotation的新特性的详细说明和使用
主要介绍了Java注解处理器简单实例,具有一定借鉴价值,需要的朋友可以参考下
java或Java框架中常用的注解及其作用详解:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过...