首頁  >  文章  >  Java  >  取得指定包下所有自訂註解

取得指定包下所有自訂註解

巴扎黑
巴扎黑原創
2017-06-23 15:26:302911瀏覽

Reflections 透過掃描 classpath,索引元數據,允許在運行時查詢這些元數據,也可以保存收集項目中多個模組的元數據資訊。

使用Reflections快速掃描指定包下自訂的Controller和RequestMapping兩個註解,先去掃描加了@Controller註解的類,接著獲取這些類下面加了@RequestMapping註解的方法,然後透過Java的反射invoke方法去呼叫加了RequestMapping註解的方法並輸出註解上的資訊。

Maven 專案導入

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

annotation套件下面自訂了兩個註解。

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.java

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註解

SunService. java

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 函式庫。

  • 得到某個類型的所有子類型

  • #獲得標記了某個註解的所有類型/成員變量,支援註解參數匹配。

  • 使用正規表示式獲得所有符合的資源檔案

  • #獲得所有特定簽章(包括參數,參數註解,傳回值)的方法

  • 使用註解修飾了類別/方法/成員變數等之後,這些註解不會自己生效,必須由這些註解的開發者提供相應的工具來提取並處理註解資訊(當然​​,只有當定義註解時使用了@Retention(RetentionPolicy.RUNTIME)修飾,JVM才會在裝載class檔案時提取保存在class檔案中的註解,該註解才會在運行時可見,這樣我們才能夠解析).

  • Java使用Annotation介面來代表程式元素前面的註解,該介面是所有註解的父介面。

  • java5在java.lang.reflect套件下新增了用AnnotatedElement介面代表程式中可以接受註解的程式元素.

  • AnnotatedElement介面的實作類別有:Class(類別元素)、Field(類別的成員變數元素)、Method(類別的方法元素)、Package(套件元素),每一個實作類別代表了一個可以接受註解的程式元素類型。

  • 這樣, 我們只需要獲取到Class、 Method、 Filed等這些實作了AnnotatedElement介面的類別的實例,透過該實例物件呼叫該類別中的方法(AnnotatedElement介面中抽象方法的重寫) 就可以獲得我們想要的註解資訊了。

  • 得到Class類別的實例有三種方法:

    • #利用物件呼叫getClass()方法來取得Class實例

    • 利用Class類別的靜態的forName()方法,使用類別名稱取得Class實例

    • #運用.class的方式取得Class實例,如:類別名.class

  • AnnotatedElement介面提供的抽象方法(在該介面的實作類別中重寫了這些方法):

    • T getAnnotation(Class< T> annotationClass)< T extends Annotation>為泛型參數聲明,表明A的類型只能是Annotation類型或是Annotation的子類別。
      功能:傳回該程式元素上存在的、指定類型的註解,如果該類型的註解不存在,則傳回null

    • Annotation[] getAnnotations()
      功能:傳回此元素上存在的所有註解,包括沒有顯示定義在該元素上的註解(繼承得到的)。 (如果此元素沒有註釋,則傳回長度為零的陣列。)

    • < T extends Annotation> T getDeclaredAnnotation(Class < T> annotationClass)
      功能:這是Java8新增的方法,此方法傳回直接修飾該程式元素、指定類型的註解(忽略繼承的註解)。如果該類型的註解不存在,則傳回null.

    • Annotation[] getDeclaredAnnotations()
      功能:傳回直接存在於此元素上的所有註解,該方法將忽略繼承的註釋。 (如果沒有註解直接存在於此元素上,則傳回長度為零的一個陣列。)

    • boolean isAnnotationPresent(ClassannotationClass)
      功能:判斷判斷該程式元素上是否存在指定類型的註解,如果存在則傳回true,否則回傳false。

    • <T extends Annotation> T[] getAnnotationsByTpye(Class annotationClass)
      功能: 因為java8增加了重複註解功能,因此需要使用該方法獲得修飾該程式元素、指定類型的多個註解。

    • T[] getDeclaredAnnotationsByTpye(ClassannotationClass)
      功能: 因為java8增加了重複註解功能,因此需要使用此方法獲得直接修飾該程式元素、指定類型的多個註解。

    Class提供了getMethod()、getField()以及getConstructor()方法(還有其他方法),這些方法分別取得與方法、領域變數以及建構子相關的信息,這些方法傳回Method、Field 以及Constructor型別的物件。

    以上是取得指定包下所有自訂註解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn