1、定义和描述
注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。注解的出现是在jdk1.5,但是在jdk1.5版本使用注解必须继续类的方法的重写,不能用于实现的接口中的方法实现,在jdk1.6环境下对于继续和实现都是用。
2、元注解
2.1、@Target:表示该注解可以用于什么地方,ElementType参数值有:
CONSTRUCTOR
:构造器的声明 FIELD
:域声明(包括enum
实例) LOCAL_VARIABLE
:局部变量声明 METHOD
:方法声明 PACKAGE
:包声明 PARAMETER
:参数声明 TYPE
:类、接口(包括注解类型)或enum
声明
2.2、@Retention:表示需要在什么阶段保存该注解信息,RetentionPolicy参数值有:
SOURCE
:注解将被编译器丢弃 CLASS
:注解在class文件中可用,但会被VM丢弃 RUNTIME
:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息
2.3、@Document:将注解保存在javadoc中
2.4、@Inherited:允许子类继承父类中的注解
3、基本语法
在底层代码实现中,我们自定义的注解都是自动继承java.lang.annotation.Annotation接口,类似于所有的类继承Object类。在自定义注解中,不需要书写构造、属性、方法,只有一种元素,注解类元素。
package com.geostar.geosmarter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
//前缀
String prefix() default "";
//直接指定文件位置
String[] locations() default {};
}
自定义注解还需要注意以下几点:
- 修饰符不许使用public,不可省略。
- 注解类元素只能是Java基本数据类型、String、Class、枚举、注解以及上述类型的一位数组。
- 注解类元素的名称一般使用名词。
- ()是一种特殊的写法,不是像方法一样定义参数的地方,()中间一直为空。
- default表示默认值,如果没有定义默认值,后续使用该注解时必须给注解类元素赋值。
4、自定义注解的使用
4.1、使用上面创建的自定义注解读取配置文件信息
package com.geostar.geosmarter;
@CustomAnnotation(prefix = "config",locations= {"config.properties"})
public class ConfigProperties {
private String ip;
private String port;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
@Override
public String toString() {
return "ConfigProperties [ip=" + ip + ", port=" + port + "]";
}
}
4.2、测试
package com.geostar.geosmarter;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class Test {
public static void main(String[] args) {
Class<ConfigProperties> clazz = ConfigProperties.class;
CustomAnnotation annotation = clazz.getAnnotation(CustomAnnotation.class);
String[] locations = annotation.locations();
Map<String,String> map = new HashMap<>();
for (String location: locations) {
Properties properties = new Properties();
try{
properties.load(Test.class.getClassLoader().getResourceAsStream(location.trim()));
} catch (IOException e) {
throw new IllegalStateException("Load properties [" + location + "] error", e);
}
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String key = entry.getKey().toString();
String value = entry.getValue() == null ? null : entry.getValue().toString();
map.put(key, value);
}
}
try {
String prefix = annotation.prefix();
ConfigProperties configProperties = clazz.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Introspector.IGNORE_ALL_BEANINFO);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String value = map.get(prefix + "." + pd.getName());
if (value != null) {
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(configProperties, value);
}
}
System.out.println(configProperties);
} catch (InstantiationException e) {
throw new IllegalStateException("newInstance [" + clazz + "] error", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("newInstance [" + clazz + "] error", e);
} catch (IntrospectionException e) {
throw new IllegalStateException("getBeanInfo [" + clazz + "] error", e);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("writeValue [" + clazz + "] error", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("writeValue [" + clazz + "] error", e);
}
}
}