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類型的對象。