您的关注是我最大的动力
随着软件开发的发展,xml配置已经被注解所取代,注解被越来越多的运用到我们的代码中了。如果我们想要使自己定义的注解来进行一些操作该怎么做呢?
自定义注解
在项目中新建Java文件是选择Annotation类型则会为我们创建一个注解文件。关于注解的详细介绍可以看之前写的注解详解文章。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Scope("prototype")
public @interface XyhBean {
}
上面创建的这个注解表名这是一个在运行时起作用的注解,并且只能作用于类上,而且作用的类不是一个单例。
使用场景
在我们的项目中可能会遇到这样的情况,需要一个工厂或者Map来存储一些类的信息,在之后的使用过程中通过工厂或者Map来获取到我们所需要的类。在一般情况下我们可能就会使用Map来进行这个操作。但是每当项目中新增一个类就要往Map中也操作一次,这样会非常的麻烦并且容易出现问题,因此我们使用自定义注解通过spring来帮我们操作。
ApplicationListener
在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册等等。这个时候我们就可以使用Spring提供的ApplicationListener来进行操作。
@Component
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
public static Map<String, Object> beanMap = new HashMap<>();
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
beanMap = event.getApplicationContext().getBeansWithAnnotation(XyhBean.class);
}
}
项目启动之后,读取所有注解了XyhBean注解的类放进我们事先定义好的Map中。
通过反射处理注解
上面的方法是通过Spring来帮助我们实现了一个简单的自定义注解场景,如果有更加复杂的场景的话就需要借助Java的反射来完成了。
注解处理器类库(java.lang.reflect.AnnotatedElement):
Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接口主要有如下几个实现类:
- Class:类定义
- Constructor:构造器定义
- Field:累的成员变量定义
- Method:类的方法定义
- Package:类的包定义
java.lang.reflect 包下主要包含一些实现反射功能的工具类,实际上,java.lang.reflect 包所有提供的反射API扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:
方法1. <T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
方法2. Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
方法3. boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
public class AnnotationUtil {
public static boolean getFruitInfo(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(XyhBean.class)) {
return true;
}
}
return false;
}
}
以上代码可以用来判断传进来的类是否注解了我们自己定义的注解。具体使用的方法需要根据使用场景来进行选择。
网友评论