JPA学习之前我先学习了一下注解,在很多项目的框架的底层代码中,我们都会发现一些由架构师搭建框架的时候写的一些自定义的注解,什么是注解(Annotation)?Annotation是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符。按照百度百科上解释是“它是一种由JSR-175标准选择用来描述元数据的一种工具”;Annotations仅仅是元数据,和业务逻辑无关;Annotations仅仅提供它定义的属性(类/方法/包/域)的信息。Annotations的用户(同样是一些代码)来读取这些信息并实现必要的逻辑。
-----------------------------------------------------
J2SE5.0版本在 java.lang.annotation提供了四种元注解,专门注解其他的注解:
@Documented –注解是否将包含在JavaDoc中
@Retention –什么时候使用该注解
@Target? –注解用于什么地方
@Inherited – 是否允许子类继承该注解
详细大概介绍下:
1.@Documented–
一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中(可以被例如javadoc此类的工具文档化)。
2.@Retention–
定义该注解的生命周期。
3.RetentionPolicy.SOURCE –
在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。 @Override,@SuppressWarnings都属于这类注解。
4.RetentionPolicy.CLASS –
在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
5.RetentionPolicy.RUNTIME–
始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
6.@Target –
表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。需要说明的是:属性的注解是兼容的,如果你想给7个属性都添加注解,仅仅排除一个属性,那么你需要在定义target包含所有的属性。
ElementType.TYPE:用于描述类、接口或enum声明
ElementType.FIELD:用于描述实例变量
ElementType.METHOD
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE 另一个注释
ElementType.PACKAGE 用于记录java文件的package信息
7.@Inherited –
定义该注释和子类的关系:允许子类继承父类中的注解;(如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。)
下面我就写个简单的demo来介绍下:
package com.rong.zhu.jpa;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author zhurong
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited //允许子类继承父类中的注解
//@Target(ElementType.METHOD) 不用,就默认都可以用
public @interface HelloWorld {
public String chineseName() default "杰姆";
public String enlishName() default "jim";
}
package com.rong.zhu.jpa;
/**
* @author zhurong
*
*/
public class TestCase {
@HelloWorld(chineseName="你好")
private String chineseName;
//注解中只有一个属性,可以直接命名为"value""enlishName=" 可以省略不写
@HelloWorld(enlishName="nihao")
private String enlishName;
public TestCase(String chineseName,String enlishName) {
this.chineseName = chineseName;
this.enlishName = enlishName;
}
@HelloWorld
public String print(String chineseName,String enlishName) {
System.out.println(chineseName+","+enlishName);
return chineseName+","+enlishName;
}
@HelloWorld
@Override
public String toString() {
System.out.println(this.chineseName+","+this.enlishName);
return this.chineseName+","+this.enlishName;
}
}
package com.rong.zhu.jpa;
import java.lang.reflect.Method;
/**
* @author zhurong
*
*/
public class ParseAnnotaion {
public void parse(Object obj, String methodName,String chineseName,String EnlishName) {
Method[] ms = obj.getClass().getMethods();
for (Method m : ms) {
if (m.isAnnotationPresent(HelloWorld.class)
&& methodName.equals(m.getName())) {
HelloWorld hw = m.getAnnotation(HelloWorld.class);
System.out.println("hw.chineseName:"+hw.chineseName());
System.out.println("hw.value:"+hw.enlishName());
try{
System.out.println("before invoke");
if(chineseName=="" && EnlishName==""){
m.invoke(obj,null);
}else{
m.invoke(obj,(Object)chineseName,(Object)EnlishName);
}
System.out.println("after invoke");
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
package com.rong.zhu.jpa;
/**
* @author zhurong
*
*/
public class MainTest {
public static void main(String[] args) {
TestCase tc = new TestCase("王五","wangwu");
ParseAnnotaion parseAnno = new ParseAnnotaion();
System.out.print("方法 print():");
System.out.println(" ------------------------------");
parseAnno.parse(tc, "print", "zhangsan", "lisi");
System.out.print("\n"+"方法 toString():");
System.out.println(" --------------------------------");
parseAnno.parse(tc, "toString", "", "");
}
}
运行结果:
方法 print(): ------------------------------
hw.chineseName:杰姆
hw.value:jim
before invoke
zhangsan,lisi
after invoke
方法 toString(): --------------------------------
hw.chineseName:杰姆
hw.value:jim
before invoke
王五,wangwu
after invoke
备注:在写这代码的过程中,我也遇到了一个bug,是关于发射的,这个请见我的另外一片文章:
《解析Java反射java.lang.IllegalArgumentException: wrong number of arguments》