reflections:Java非常好用的反射工具包
文章目录
- 一、写在前面
- 二、使用
一、写在前面
开源地址: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、 扫描方法、构造注解 //MethodAnnotationsScanner Set<Method> resources = reflections.getMethodsAnnotatedWith(Value.class); Set<Constructor> injectables = reflections.getConstructorsAnnotatedWith(Autowired.class); // 字段注解 Set<Field> ids = reflections.getFieldsAnnotatedWith(Autowired.class); // 6、扫描方法参数 //MethodParameterScanner Set<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\"); //参数个数为0 Predicate<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,返回值为boolean Set<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); //返回类型是boolean Predicate<Method> returnPredicate = ReflectionUtils.withReturnType(boolean.class); methods = ReflectionUtils.getAllMethods(LinkedList.class, paramsPredicate, returnPredicate); methods.forEach(method -> System.out.println(method.getName())); System.out.println(\"---------------\"); //字段有注解Native Predicate<Field> annotationPredicate = ReflectionUtils.withAnnotation(Native.class); //字段类型是int及其子类 Predicate<Field> typeAssignablePredicate = ReflectionUtils.withTypeAssignableTo(int.class); Set<Field> fields = ReflectionUtils.getAllFields(Integer.class, annotationPredicate, typeAssignablePredicate);// Set fields = ReflectionUtils.getAllFields(Integer.class, annotationPredicate);// Set fields = ReflectionUtils.getAllFields(Integer.class, typeAssignablePredicate); fields.forEach(field -> System.out.println(field.getName())); }}