獲取指定包下全部自定義註解

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();
        }
    }
}

運行獲得:

其餘

  1. 使用 Reflections 能夠查詢如下元數據信息:
    • 得到某個類型的全部子類型
    • 得到標記了某個註解的全部類型/成員變量,支持註解參數匹配。
    • 使用正則表達式得到全部匹配的資源文件
    • 得到全部特定簽名(包括參數,參數註解,返回值)的方法

    Reflections 依賴 Google 的 Guava 庫和 Javassist 庫。

  2. 使用註解修飾了類/方法/成員變量等以後,這些註解不會本身生效,必須由這些註解的開發者提供相應的工具來提取並處理註解信息(固然,只有當定義註解時使用了@Retention(RetentionPolicy.RUNTIME)修飾,JVM纔會在裝載class文件時提取保存在class文件中的註解,該註解纔會在運行時可見,這樣咱們纔可以解析).

  3. Java使用Annotation接口來表明程序元素前面的註解,該接口是全部註解的父接口。

  4. java5在java.lang.reflect包下新增了 用AnnotatedElement接口表明程序中能夠接受註解的程序元素.

  5. AnnotatedElement接口的實現類有:Class(類元素)、Field(類的成員變量元素)、Method(類的方法元素)、Package(包元素),每個實現類表明了一個能夠接受註解的程序元素類型。

  6. 這樣, 咱們只須要獲取到Class、 Method、 Filed等這些實現了AnnotatedElement接口的類的實例,經過該實例對象調用該類中的方法(AnnotatedElement接口中抽象方法的重寫) 就能夠獲取到咱們想要的註解信息了。

  7. 得到Class類的實例有三種方法:

    • 利用對象調用getClass()方法得到Class實例
    • 利用Class類的靜態的forName()方法,使用類名得到Class實例
    • 運用.class的方式得到Class實例,如:類名.class
  8. AnnotatedElement接口提供的抽象方法(在該接口的實現類中重寫了這些方法):
    • <T extends Annotation> T getAnnotation(Class< T> annotationClass)&lt T extends Annotation>爲泛型參數聲明,代表A的類型只能是Annotation類型或者是Annotation的子類。
      功能:返回該程序元素上存在的、指定類型的註解,若是該類型的註解不存在,則返回null
    • Annotation[] getAnnotations()
      功能:返回此元素上存在的全部註解,包括沒有顯示定義在該元素上的註解(繼承獲得的)。(若是此元素沒有註釋,則返回長度爲零的數組。)
    • < T extends Annotation> T getDeclaredAnnotation(Class < T> annotationClass)
      功能:這是Java8新增的方法,該方法返回直接修飾該程序元素、指定類型的註解(忽略繼承的註解)。若是該類型的註解不存在,返回null.
    • Annotation[] getDeclaredAnnotations()
      功能:返回直接存在於此元素上的全部註解,該方法將忽略繼承的註釋。(若是沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)
    • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
      功能:判斷該程序元素上是否存在指定類型的註解,若是存在則返回true,不然返回false。
    • &ltT extends Annotation> T[] getAnnotationsByTpye(Class<T> annotationClass)
      功能: 由於java8增長了重複註解功能,所以須要使用該方法得到修飾該程序元素、指定類型的多個註解。
    • <T extends Annotation> T[] getDeclaredAnnotationsByTpye(Class<T>annotationClass)
      功能: 由於java8增長了重複註解功能,所以須要使用該方法得到直接修飾該程序元素、指定類型的多個註解。

Class提供了getMethod()、getField()以及getConstructor()方法(還有其餘方法),這些方法分別獲取與方法、域變量以及構造函數相關的信息,這些方法返回Method、Field 以及Constructor類型的對象。

相關文章
相關標籤/搜索