Reflections 经过扫描 classpath,索引元数据,容许在运行时查询这些元数据,也能够保存收集项目中多个模块的元数据信息。java
使用Reflections快速扫描指定包下自定义的Controller和RequestMapping两个注解,先去扫描加了@Controller注解的类,接着获取这些类下面加了@RequestMapping注解的方法,而后经过Java的反射invoke方法去调用加了RequestMapping注解的方法并输出注解上的信息。正则表达式
Maven 项目导入数组
<dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency>
annotation包下面自定义了两个注解。app
Controller.java:函数
package annotationTest.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE)// 注解会在class字节码文件中存在,在运行时能够经过反射获取到 @Retention(RetentionPolicy.RUNTIME)//定义注解的做用目标**做用范围字段、枚举的常量/方法 @Documented//说明该注解将被包含在javadoc中 public @interface Controller { String value() default ""; }
RequestMapping.java工具
package annotationTest.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { String value() default ""; /** * 是否为序列号 * * @return */ boolean id() default false; /** * 字段名称 * * @return */ String name() default ""; /** * 字段描述 * * @return */ String description() default ""; }
在model包下面定义了一个存放RequestMapping注解方法的对象测试
ExecutorBean.javathis
package annotationTest.model; import java.lang.reflect.Method; public class ExecutorBean { private Object object; private Method method; public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } }
service包下面定义了几个类,其中有两个类使用了自定义的Controller注解url
SunService.javaspa
package annotationTest.service; import annotationTest.annotation.Controller; import annotationTest.annotation.RequestMapping; @Controller public class SunService { @RequestMapping(id = true, name = "test1", description = "sun测试1", value = "/test1") public void test1() { System.out.println("SunService->test1()"); } @RequestMapping(id = true, name = "test2", description = "sun测试2", value = "/test2") public void test2() { System.out.println("SunService->test2()"); } }
MoonService.java
package annotationTest.service; import annotationTest.annotation.Controller; import annotationTest.annotation.RequestMapping; @Controller public class MoonService { @RequestMapping(id = true, name = "moon测试3", description = "/test3", value = "/test3") public void test3() { System.out.println("MoonService->test3()"); } @RequestMapping(id = true, name = "moon测试4", description = "/test4", value = "/test4") public void test4() { System.out.println("MoonService->test4()"); } }
Stars.java
package annotationTest.service; import annotationTest.annotation.RequestMapping; public class Stars { @RequestMapping(id = true, name = "test1", description = "stars测试1", value = "/test1") public void test1() { System.out.println("Stars->test1()"); } }
util包下面定义了一个工具类,来对包进行扫描获取自定义注解的类和方法
AnnoManageUtil.java
package annotationTest.util; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Set; import annotationTest.annotation.Controller; import annotationTest.annotation.RequestMapping; import annotationTest.model.ExecutorBean; import org.reflections.Reflections; public final class AnnoManageUtil { /** * 获取指定文件下面的RequestMapping方法保存在mapp中 * * @param packageName * @return */ public static Map<String, ExecutorBean> getRequestMappingMethod(String packageName) { Reflections reflections = new Reflections(packageName); Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(Controller.class); // 存放url和ExecutorBean的对应关系 Map<String, ExecutorBean> mapp = new HashMap<String, ExecutorBean>(); for (Class classes : classesList) { //获得该类下面的全部方法 Method[] methods = classes.getDeclaredMethods(); for (Method method : methods) { //获得该类下面的RequestMapping注解 RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); if (null != requestMapping) { ExecutorBean executorBean = new ExecutorBean(); try { executorBean.setObject(classes.newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } executorBean.setMethod(method); mapp.put(requestMapping.value(), executorBean); } } } return mapp; } }
test包下面是一个测试的类
package annotationTest.test; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.List; import java.util.Map; import annotationTest.annotation.Controller; import annotationTest.annotation.RequestMapping; import annotationTest.model.ExecutorBean; import annotationTest.util.AnnoManageUtil; public class Test { public static void main(String[] args) { List<Class<?>> classesList = null; classesList = AnnoManageUtil.getPackageController("annotationTest.service", Controller.class); Map<String, ExecutorBean> mmap = new HashMap<String, ExecutorBean>(); AnnoManageUtil.getRequestMappingMethod(classesList, mmap); ExecutorBean bean = mmap.get("/test1"); try { bean.getMethod().invoke(bean.getObject()); RequestMapping annotation = bean.getMethod().getAnnotation(RequestMapping.class); System.out.println("注解名称:" + annotation.name() + "\t注解描述:" + annotation.description()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
运行获得:
其余
Reflections 依赖 Google 的 Guava 库和 Javassist 库。
使用注解修饰了类/方法/成员变量等以后,这些注解不会本身生效,必须由这些注解的开发者提供相应的工具来提取并处理注解信息(固然,只有当定义注解时使用了@Retention(RetentionPolicy.RUNTIME)修饰,JVM才会在装载class文件时提取保存在class文件中的注解,该注解才会在运行时可见,这样咱们才可以解析).
Java使用Annotation接口来表明程序元素前面的注解,该接口是全部注解的父接口。
java5在java.lang.reflect包下新增了 用AnnotatedElement接口表明程序中能够接受注解的程序元素.
AnnotatedElement接口的实现类有:Class(类元素)、Field(类的成员变量元素)、Method(类的方法元素)、Package(包元素),每个实现类表明了一个能够接受注解的程序元素类型。
这样, 咱们只须要获取到Class、 Method、 Filed等这些实现了AnnotatedElement接口的类的实例,经过该实例对象调用该类中的方法(AnnotatedElement接口中抽象方法的重写) 就能够获取到咱们想要的注解信息了。
得到Class类的实例有三种方法:
Class提供了getMethod()、getField()以及getConstructor()方法(还有其余方法),这些方法分别获取与方法、域变量以及构造函数相关的信息,这些方法返回Method、Field 以及Constructor类型的对象。