一、寫在前面
開源地址:https://github.com/ronmamo/reflections
目前項目已經出于不活躍狀態,JDK8還是支持的,但是JDK11以上就會有問題。
Reflections 會掃描并索引您項目類路徑的元數據,允許在運行時反向傳遞查詢
類型系統。
核心功能:
掃描預定義的URLs: Reflections可以掃描項目的類路徑、特定的目錄或者JAR文件,來查找特定的類型或者帶有特定注解的元素。
查詢元數據信息: 一旦掃描完成,Reflections允許你查詢這些元數據信息,例如獲取所有帶有特定注解的類或者方法。
索引化視圖: Reflections創建了一個索引化的視圖,用于在運行時快速訪問掃描結果。
支持多種掃描器: Reflections支持多種掃描器,包括類掃描器、字段掃描器、方法掃描器等,每種掃描器都可以用來查找特定的元素。
在使用 Java 的 Reflections 庫掃描類時,默認情況下會
加載類
。
這是因為 Reflections 庫的工作原理是基于類路徑掃描,它需要讀取類的字節碼信息
來分析類的結構、繼承關系、注解等元數據。當它找到符合條件的類時,會通過類加載器將類加載到 JVM 中,以便獲取完整的類信息(如 Class 對象)。
類加載的過程會觸發類的靜態初始化塊(static {}
)執行,這一點需要特別注意。
大量類被加載可能增加JVM 內存
占用,尤其在掃描范圍過大時
性能考慮
:避免在頻繁執行的路徑上使用Reflections,因為初始化可能比較耗時。
使用緩存
:對于不變的查詢結果,利用Reflections提供的緩存機制來提高性能。
<dependency><groupId>org.reflections</groupId><artifactId>reflections</artifactId><version>0.10.2</version>
</dependency>
二、使用
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;import javax.websocket.server.PathParam;
import java.lang.annotation.Native;
import java.lang.reflect.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;public class Test {public static void main(String[] args) throws Exception {// 指定包名Reflections reflections = new Reflections("com.demo");// 1、獲取所有被 @RestController 注解的類Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(RestController.class);// 如果是嵌套注解,是無法獲取的Set<Class<?>> annotated2 = reflections.getTypesAnnotatedWith(Controller.class);System.out.println(annotated);System.out.println(annotated2);/*** 2、創建Reflections實例: Reflections類的實例化是通過一個配置對象ConfigurationBuilder進行的。** 配置輸入過濾器:* .filterInputsBy(new FilterBuilder().includePackage(INIT_PATH))* 這行設置了輸入過濾器,它決定了哪些類會被掃描。這里使用了FilterBuilder來包含一個特定的包路徑INIT_PATH。** 設置URLs:* .setUrls(ClasspathHelper.forPackage(INIT_PATH))* 這行代碼設置了Reflections掃描的URLs。ClasspathHelper.forPackage是通過包路徑查找類路徑URLs的實用方法。它會搜索與INIT_PATH包相關的所有URLs,并將它們提供給Reflections庫,以便掃描。** 添加掃描器:* new TypeAnnotationsScanner():掃描所有帶注解的類型(類、接口等)。* new MethodParameterScanner():掃描所有方法的參數。* new MethodAnnotationsScanner():掃描所有帶注解的方法。* new FieldAnnotationsScanner():掃描所有帶注解的字段。* 這些掃描器指定了Reflections需要收集哪些元數據。** 整個代碼塊的目的是配置Reflections實例以搜索和索引特定包"com.demo"中的類、方法、參數和字段的注解信息,* 以便可以快速訪問這些元數據而不必逐個類地使用Java反射API。*/final Reflections reflections2 = new Reflections(new ConfigurationBuilder().filterInputsBy(new FilterBuilder().includePackage("com.demo")).setUrls(ClasspathHelper.forPackage("com.demo")).addScanners(new TypeAnnotationsScanner(),new MethodParameterScanner(),new MethodAnnotationsScanner(),new FieldAnnotationsScanner()));// 3、得到某接口下的所有實現類,子類Set<Class<? extends BeanPostProcessor>> implClassSet=reflections.getSubTypesOf(BeanPostProcessor.class);for (Class<? extends BeanPostProcessor> aClass : implClassSet) {BeanPostProcessor beanPostProcessor = aClass.newInstance();// 。。。}// 4、ResourcesScanner 掃描資源Set<String> properties =reflections.getResources(Pattern.compile(".*\\.properties"));// 5、 掃描方法、構造注解//MethodAnnotationsScannerSet<Method> resources =reflections.getMethodsAnnotatedWith(Value.class);Set<Constructor> injectables =reflections.getConstructorsAnnotatedWith(Autowired.class);// 字段注解Set<Field> ids =reflections.getFieldsAnnotatedWith(Autowired.class);// 6、掃描方法參數//MethodParameterScannerSet<Method> someMethods =reflections.getMethodsWithSignature(long.class, int.class);Set<Method> voidMethods =reflections.getMethodsReturn(void.class);Set<Method> pathParamMethods =reflections.getMethodsAnnotatedWith(PathParam.class);List<String> parameterNames =reflections.getMemberParameterNames(method);//MemberUsageScanner 方法調用情況Set<Member> usages =reflections.getMemberUsage(class);}/*** 工具類的使用*/public void reflectionUtils(){//必須是public方法Predicate<Method> publicPredicate = ReflectionUtils.withModifier(Modifier.PUBLIC);//有get前綴Predicate<Method> getPredicate = ReflectionUtils.withPrefix("get");//參數個數為0Predicate<Member> paramPredicate = ReflectionUtils.withParametersCount(0);Set<Method> methods = ReflectionUtils.getAllMethods(LinkedList.class, publicPredicate, getPredicate, paramPredicate);methods.forEach(method -> System.out.println(method.getName()));// 根據方法的可見性,前綴名,入參個數,獲取某個類的對應方法Set<Method> getters = ReflectionUtils.getAllMethods(User.class,ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("set"), ReflectionUtils.withParametersCount(1));//獲取List的方法:入參為Collection,返回值為booleanSet<Method> methods2 = ReflectionUtils.getAllMethods(List.class,ReflectionUtils.withParametersAssignableTo(Collection.class),ReflectionUtils.withReturnType(boolean.class));//該方法可以傳入一些參數,比如過濾出帶注解的參數:withAnnotation(NonNull.class)Set<Field> fields2 = ReflectionUtils.getAllFields(Animal.class, ReflectionUtils.withTypeAssignableTo(String.class));System.out.println("---------------");//參數必須是Collection及其子類Predicate<Member> paramsPredicate = ReflectionUtils.withParametersAssignableTo(Collection.class);//返回類型是booleanPredicate<Method> returnPredicate = ReflectionUtils.withReturnType(boolean.class);methods = ReflectionUtils.getAllMethods(LinkedList.class, paramsPredicate, returnPredicate);methods.forEach(method -> System.out.println(method.getName()));System.out.println("---------------");//字段有注解NativePredicate<Field> annotationPredicate = ReflectionUtils.withAnnotation(Native.class);//字段類型是int及其子類Predicate<Field> typeAssignablePredicate = ReflectionUtils.withTypeAssignableTo(int.class);Set<Field> fields = ReflectionUtils.getAllFields(Integer.class, annotationPredicate, typeAssignablePredicate);
// Set<Field> fields = ReflectionUtils.getAllFields(Integer.class, annotationPredicate);
// Set<Field> fields = ReflectionUtils.getAllFields(Integer.class, typeAssignablePredicate);fields.forEach(field -> System.out.println(field.getName()));}
}