相信很多Javaer在学习Java的过程中,最先接触到的注解应该是@Override了。随着学习的深入,我们开始学习一些开源框架,比如Spring、Hibernate、MyBatis等,这就需要我们对注解有一定的了解。
1、什么是注解
注解是那些插入到代码中,使用其他工具可以对其进行处理的标签,在Java中,注解是当做一个修饰符来使用(比如public、static之类的关键词),它被放在被注解项之前。每一个注解的名称前面都加上了@符号。其实不用把注解想的太神奇,它类似于Javadoc注释,用来说明一个类的各个部分的作用,注解本身不会做任何事情,需要工具去解析才会有用。
2、自定义注解
注解是由注解接口@interface来定义的,一般注解都会有如下所示的格式:
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
int value();
String name() default "[none]";
}
初看起来注解都和java的接口类似,注解里面的方法叫做注解的元素,但是一个注解方法不能有任何的参数和throws语句。上面的注解定义了两个元素。每个元素声明都具有一下两种形式:
// 不带默认值
type elementName();
// 带默认值
Type elementName() default value;
使用的时候也有几种方式
// 元素的顺序不重要
@CustomAnnotation(value = 0, name = "name")
// 如果某个元素有默认值可不列出
@CustomAnnotation(value = 0)
// 如果只有一个元素是必填的,并且名字是value,可以不指定元素名
@CustomAnnotation(0)
注解元素的类型为下列之一:
基本类型:byte、short、int、long、float、double、char、boolean。
String。
Class(具有一个可选的类型参数,例如Class<? extends OtherClass>)。
enum。
注解类型。
由上面所述的类型数组。
一个项可以具有多个注解,只要这些注解不是同一个类型即可,注解可以用来注解包、类、接口、方法、构造器、实例域、局部变量、参数变量。
3、元注解
Java提供了@Target、@Retention、@Inherited和@Documented这4个元注解,来提供新建注解时使用。
@Target元注解可以应用于一个注解,用来限制该注解可以用到哪些项上。例如
@Target({ ElementType.FIELD, ElementType.METHOD })
表明这个注解可以应用在实例域和方法上面,ElementType有以下几种常用的类型:
FIELD:实例
METHOD:方法
PARAMETER:方法或构造器参数
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型说明
PACKAGE:包
TYPE:类(包括enum)和接口
如果一个注解没有使用@Target限制,那么该注解可以应用到任何项上面,加了@Target限制之后,如果没有把注解应用到对应的项,则会导致编译器错误。
@Retention元注解用于指定注解应该保留多长时间,默认的值是RetentionPolicy.CLASS
SOURCE:不包括在类文件中,只存在源码中
CLASS:包括在类文件中,但是虚拟机不需要将它们载入
RUNTIME:包括在类文件中,虚拟机将会载入,并且可以通过反射API来获取
@Inherited元注解只能用于对类的注解,如果一个类具有@Inherited元注解,那么它的所有子类都自动具有相同的注解
@Documented元注解为像Javadoc这样的归档工具提供一些提示。对于工具开发者来所,一般很少会用到,这里就不详细说明。
4、注解处理
前文说到注解本身不会做任何事情,只是说明一个类各个部分的作用。但是配合Java的反射特性,注解可以发挥很大的作用。这里先给一个例子:
package org.jackie.annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AnnotationHandler {
private static Logger logger = LoggerFactory.getLogger(AnnotationHandler.class);
/**
* 生成一个T的实例,并把V中带有PropertyMapping的属性的值付给T实例中对应的属性
* @param source
* @param targetClass
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static <V, T> T processAnnotation(V source, Class<T> targetClass) {
T t = null;
try {
t = targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
logger.error("processAnnotation方法执行出错:", e);
throw new PropertyMappingException("对象没有默认构造器或者无法被实例化!");
}
AnnotationHandler.processAnnotation(source, t);
return t;
}
/**
* 把source中带有PropertyMapping的属性的值付给T中对应的属性
* @param source
* @param target
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static <V, T> void processAnnotation(V source, T target) {
Class<?> sourceClass = source.getClass();
Field[] fileds = sourceClass.getDeclaredFields();
if (fileds != null && fileds.length > 0) {
for (Field filed : fileds) {
PropertiesMapping mappings = filed.getAnnotation(PropertiesMapping.class);
if (mappings != null) {
PropertyMapping[] annotations = mappings.mappings();
for (PropertyMapping annotation : annotations) {
AnnotationHandler.processPropertyMapping(annotation, filed, source, target);
}
} else {
PropertyMapping annotation = filed.getAnnotation(PropertyMapping.class);
AnnotationHandler.processPropertyMapping(annotation, filed, source, target);
}
}
}
}
private static <V, T> void processPropertyMapping(PropertyMapping annotation, Field filed, V source, T t) {
if (annotation != null) {
filed.setAccessible(true);
Object filedValue = null;
try {
filedValue = filed.get(source);
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("反射获取属性值出错:", e);
throw new PropertyMappingException("属性不能被访问!");
}
if (filedValue == null) {
return;
}
// 目标类属性名
String targetPropertyName = null;
// 目标类属性的Java类型
Class<?> targetPropertyType = null;
// 目标类属性的值
Object tergetPropertyValue = null;
Method targetGetter = null;
Method targetSetter = null;
Class<?> targetClass = t.getClass();
// 获取目标属性的属性名
String property = annotation.property();
targetPropertyName = AnnotationConstant.STRING_DEFAULT_VALUE.equals(property) ? filed.getName() : property;
try {
targetGetter = targetClass.getDeclaredMethod("get" + firstLetterUpper(targetPropertyName));
} catch (NoSuchMethodException | SecurityException e) {
logger.error("反射获取getter出错:", e);
throw new PropertyMappingException(targetClass.getName() + ",不存在属性:" + targetPropertyName);
}
// 类型转换器
String convertorName = annotation.convertor();
if (!AnnotationConstant.STRING_DEFAULT_VALUE.equals(convertorName)) {
try {
@SuppressWarnings("unchecked")
Convertible<Object, ?> convertor = (Convertible<Object, ?>) Class.forName(convertorName)
.newInstance();
tergetPropertyValue = convertor.convert(filedValue);
targetPropertyType = tergetPropertyValue.getClass();
} catch (InstantiationException | IllegalAccessException e) {
logger.error("对象没有默认构造器或者无法被实例化:", e);
throw new PropertyMappingException("对象没有默认构造器或者无法被实例化!");
} catch (ClassNotFoundException e) {
logger.error("转换器类不存在:", e);
throw new PropertyMappingException("转换器类:" + convertorName + "不存在!");
}
} else {
tergetPropertyValue = filedValue;
targetPropertyType = targetGetter.getReturnType();
}
try {
targetSetter = targetClass.getDeclaredMethod("set" + firstLetterUpper(targetPropertyName), targetPropertyType);
} catch (NoSuchMethodException | SecurityException e) {
logger.error("反射获取setter出错:", e);
throw new PropertyMappingException("属性不存在setter!");
}
try {
targetSetter.invoke(t, tergetPropertyValue);
} catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
logger.error("反射执行invoke出错:", e);
throw new PropertyMappingException(targetPropertyName + ",属性的值非:" + targetPropertyType);
}
}
}
/**
* 首字母大写
*
* @param string
* @return
*/
private static String firstLetterUpper(String string) {
if (string == null) {
return "";
}
char[] c = string.toCharArray();
if (c[0] >= 'a' && c[0] <= 'z') {
c[0] = (char) (c[0] - 32);
}
return new String(c);
}
}
package org.jackie.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ FIELD, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyMapping {
String property() default AnnotationConstant.STRING_DEFAULT_VALUE;
/**
* 指定一个实现了Convertible接口的类
* @return
*/
String convertor() default AnnotationConstant.STRING_DEFAULT_VALUE;
}
package org.jackie.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ FIELD, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertiesMapping {
PropertyMapping[] mappings();
}
package org.jackie.annotation;
public class AnnotationConstant {
/**
* PropertyMapping注解字符串属性的默认值
*/
public static final String STRING_DEFAULT_VALUE = "[none]";
}
package org.jackie.annotation;
/**
* 把源类型S,转换为目标类型T
* @param <S>
* @param <T>
*/
public interface Convertible<S, T> {
T convert(S s);
}
package org.jackie.annotation;
public class PropertyMappingException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PropertyMappingException() {
super("属性映射异常:目标类不存在该属性!");
}
public PropertyMappingException(String message) {
super(message);
}
}