从JDK1.5后Java开发提供了Annotation技术支持,这种技术项目的设计与编写带来了新的模型,而后经过了十多年的发展,Annotation的技术得到了非常广泛的应用,并且在所有的项目开发中都会存在。
获取Annotation信息
在进行类或方法定义时,都可以使用一系列的Annotation进行声明,于是如果要想获得这些Annotation信息,那么可以直接通过反射来完成。在java.lang.reflect包中AccessibleObject类,在本类中提供有获取Annotation类的方法:
- 获取全部Annotation:
public Annotation[] getAnnotations()
- 获取指定Annotation:
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
范例:定义一个接口,并在接口在使用Annotation
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@FunctionalInterface//程序执行时可以获取
@Deprecated(since = "1.0")//程序执行时可以获取
interface IMessage {//有2个Annotation
void send(String message);
}
@SuppressWarnings("serial")//该Annotation无法在程序执行时获取
class MessageImpl implements IMessage, Serializable {
@Override//无法在程序执行时获取
public void send(String message) {
System.out.println("【消息发送】" + message);
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
{//获取IMessage接口上的Annotation信息
Annotation[] annotations = IMessage.class.getAnnotations();//获取接口上的全部Annotation
for (Annotation annotation : annotations) {
System.out.println(annotation);
//@java.lang.FunctionalInterface()
//@java.lang.Deprecated(forRemoval=false, since="1.0")
}
}
System.out.println("-----------------------");
{//获取MessageImpl类上的Annotation信息
Annotation[] annotations = MessageImpl.class.getAnnotations();//获取类上的全部Annotation
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
System.out.println("-----------------------");
{//获取MessageImpl.send()方法上的Annotation信息
Method method = MessageImpl.class.getDeclaredMethod("send", String.class);
Annotation[] annotations = method.getAnnotations();//获取方法上的全部Annotation
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
}
不同的Annotation有它的存在范围,下面对比两个Annotation:
@FunctionalInterface(运行时):
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
@SuppressWarnings(源代码):
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {}
现在发现“@FunctionalInterface”是在运行时生效的,所以程序执行时可以获取;
“@SuppressWarnings”是在源代码编写时有效;
在RetentionPolicy枚举类中还有一个class的定义,指的是在类定义时生效。
自定义Annotation
现在已经清楚了Annotation的获取,以及Annotation的运行策略,但是最为关键性的因素是如何实现自定义的Annotation呢?为此在Java中提供了新的语法,使用“@interface”来定义Annotation。
范例:自定义Annotation
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
@Retention(RetentionPolicy.RUNTIME)//定义Annotation的运行策略
@interface DefaultAnnotation {//自定义的Annotation
String title();//标题
String url() default "www.baidu.com";//地址,默认值
}
class Message {
@DefaultAnnotation(title = "MLDN")
public void send(String message) {
System.out.println("【消息发送】" + message);
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
Method method = Message.class.getMethod("send",String.class);
DefaultAnnotation annotation = method.getAnnotation(DefaultAnnotation.class);
// //直接调用Annotation中的方法
String message = annotation.title()+"("+annotation.url()+")";
Object obj= Message.class.getDeclaredConstructor().newInstance();
method.invoke(obj, message);//【消息发送】MLDN(www.baidu.com)
}
}
使用Annotation后的最大特点是可以结合反射机制实现程序的处理。
工厂设计模式与Annotation整合
现在已经清楚了Annotation的整体作用,但是Annotation到底在开发中能做哪些事情呢?为了进一步理解Annotation的处理目的,下面将结合工厂设计模式来应用Annotation操作。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
MessageService service=new MessageService();
service.send("www.baidu.com");
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface UserMessage{
Class <?> clazz();
}
@UserMessage(clazz =NetMessageImpl.class )
class MessageService{
private IMessage message;
public MessageService(){
UserMessage userMessage=MessageService.class.getAnnotation(UserMessage.class);
Class<?> clazz=userMessage.clazz();
this.message = (IMessage)Factory.getInstance(clazz);
}
public void send(String message){
this.message.send(message);
}
}
class Factory {
private Factory() {}
public static <T> T getInstance(Class<T> clazz){
//直接返回一个实例化对象
try {
return (T)new MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
interface IMessage {
void send(String message);
}
class MessageImpl implements IMessage {
@Override
public void send(String message) {
System.out.println("【消息发送】"+message);
}
}
class NetMessageImpl implements IMessage {
@Override
public void send(String message) {
System.out.println("【网络消息发送】"+message);
}
}
class MessageProxy implements InvocationHandler {
private Object target;
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public boolean connect(){
System.out.println("【代理操作】进行消息发送通道的连接。");
return true;
}
public void close() {
System.out.println("【代理操作】关闭连接通道");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if(connect()){
return method.invoke(target, args);
}
throw new Exception("【ERROR】消息无法进行发送!");
}finally {
close();
}
}
}
由于Annotation的存在,所以面向接口的编程处理将可以直接利用Annotation的属性完成控制,从而使得整体代码变得整洁。