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提供的缓存机制来提高性能。

xml 复制代码
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.10.2</version>
</dependency>

二、使用

java 复制代码
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<Field> fields = ReflectionUtils.getAllFields(Integer.class, annotationPredicate);
//        Set<Field> fields = ReflectionUtils.getAllFields(Integer.class, typeAssignablePredicate);
        fields.forEach(field -> System.out.println(field.getName()));


    }
}
相关推荐
float_六七7 分钟前
JavaScript:现代Web开发的核心动力
开发语言·前端·javascript
一车小面包8 分钟前
Python高级入门Day6
开发语言·python
祁同伟.13 分钟前
【C++】类和对象(中)构造函数、析构函数
开发语言·c++
forestsea25 分钟前
Caffeine 缓存库的常用功能使用介绍
java·缓存·caffeine
辉辉健身中1 小时前
HttpServletRequest知识点
java
a cool fish(无名)1 小时前
rust-方法语法
开发语言·后端·rust
摸鱼仙人~1 小时前
HttpServletRequest深度解析:Java Web开发的核心组件
java·开发语言·前端
nbsaas-boot1 小时前
收银系统优惠功能架构:可扩展设计指南(含可扩展性思路与落地细节)
java·大数据·运维
你过来啊你1 小时前
Java面向对象思想解析
android·java
郝学胜-神的一滴1 小时前
C++ 类型萃取:深入理解与实践
开发语言·c++·程序人生