反射工具—Reflections

michael-kroul-bTZU6EwVEQs-unsplash.jpg

今天做项目的时候有一个需求,需要去指定包路径下找到自定义注解的Class, 虽然项目使用使用的springboot, 可以将这个Class放到IOC容器中,然后通过BeanFacotry根据指定注解获取出来,但实际上我并不需要将他们放到容器中,就是单纯的获取一下标注特定注解的Class做些处理。

后面发现了一个比较好用的反射框架: Reflections。使用Reflections可以很轻松的获取以下数据:

  • 获取某个类型的全部子类
  • 获取指定注解的类,方法,属性等等
  • 获取所有能匹配某个正则表达式的资源
  • 获取所有带有特定签名的方法,包括参数,参数注解,返回类型
  • 获取代码里所有字段、方法名、构造器的使用

大家可以去github上看看,它里面列举了很多常用的例子。我这里也是搬过来简单说下,当做自己的一个笔记。

首先要导入它的依赖。

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

1. 简单使用

先定义一个接口和两个抽象类:

package com.qiuguan.demo.service;





public interface UserService {





    void login();
}





public class UserServiceImpl implements UserService {




    @MyAnnotation
    @Override
    public void login() {


    }
}

public class UserServiceExtImpl implements UserService {


    @MyAnnotation
    @Override
    public void login() {

    }
}

自定义一个注解:

package com.qiuguan.demo.anns;





@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnnotation {




}

自定义两个类:

package com.qiuguan.demo.bean;





public abstract class AbstractAnimal {





}








@MyAnnotation
public class Cat extends AbstractAnimal {




    private String name;
    
    @MyAnnotation
    public void eat() {
        
    }
}


进入正题:

import static org.reflections.scanners.Scanners.TypesAnnotated;





public class ReflectionTest {






    public static void main(String[] args) {





        //这里如果不指定扫描的包路径,那么它会根据类加载器把项目中的类路径以及jar包都会扫描,会比较慢,所以最好指定路径
        Reflections reflections = new Reflections("com.qiuguan.demo");





        //标注了该注解的所有类
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyAnnotation.class);
        typesAnnotatedWith.forEach(System.out::println);
        
        //或者这种写法
        Set<Class<?>> classes = reflections.get(TypesAnnotated.of(MyAnnotation.class).asClass());
        classes.forEach(System.out::println);
    }
}

输出结果:class com.qiuguan.demo.bean.Cat

import static org.reflections.scanners.Scanners.*;





public class ReflectionTest {






    public static void main(String[] args) {





        /**
         * 这里如果不指定扫描的包路径,那么它会根据类加载器把项目中的类路径以及jar包都会扫描,会比较慢,所以最好指定路径
         * 参考 {@link Scanners } 类,配置不同的Scanner, 比如扫描类注解,方法注解,子类等等。
         */
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .forPackage("com.qiuguan.demo")
                //这里要和上面保持一致保持一致,不写也不行,不然输出结果不对。没有特殊要求,就用String参数的构造器
                .filterInputsBy(new FilterBuilder().includePackage("com.qiuguan.demo"))
                //包含包和排除包路径。写excludePackage前要先写includePackage,不然排除包不会生效
                //.filterInputsBy(new FilterBuilder().includePackage("com.qiuguan.demo").excludePackage("com.qiuguan.boot"))
                .setScanners(TypesAnnotated, Scanners.MethodsAnnotated, SubTypes, MethodsReturn)
        );



        System.out.println("=================== 获取标注该注解的所有类 =======================");
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyAnnotation.class);
        typesAnnotatedWith.forEach(System.out::println);

        System.out.println("==================== 获取标注该注解的所有方法 ======================");

        //获取标注了该注解的所有方法
        Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(MyAnnotation.class);
        methodsAnnotatedWith.forEach(System.out::println);


        System.out.println("==================== 获取接口的所有子类  ==========================");

        //获取某个接口或者父类的所有子类
        Set<Class<? extends UserService>> subTypesOf = reflections.getSubTypesOf(UserService.class);
        subTypesOf.forEach(System.out::println);

        System.out.println("==================== 获取返回值是void的方法  ==========================");

        Set<Method> methodsReturn = reflections.getMethodsReturn(void.class);
        methodsReturn.forEach(System.out::println);
    }
}
23:51:55.921 [main] INFO org.reflections.Reflections - Reflections took 172 ms to scan 1 urls, producing 13 keys and 22 values
=================== 获取标注该注解的所有类 =======================

class com.qiuguan.demo.bean.Cat

==================== 获取标注该注解的所有方法 ======================
public void com.qiuguan.demo.bean.UserServiceExtImpl.login()
public void com.qiuguan.demo.bean.UserServiceImpl.login()
public void com.qiuguan.demo.bean.Cat.eat()
==================== 获取接口的所有子类  ==========================
class com.qiuguan.demo.bean.UserServiceExtImpl
class com.qiuguan.demo.bean.UserServiceImpl
==================== 获取特定返回值的方法  ==========================
public void com.qiuguan.demo.bean.UserServiceExtImpl.login()
public static void com.qiuguan.demo.MainApplication.main(java.lang.String[])
public void com.qiuguan.demo.bean.UserServiceImpl.login()
public abstract void com.qiuguan.demo.bean.UserService.login()
public static void com.qiuguan.demo.reflections.ReflectionTest.main(java.lang.String[])
public void com.qiuguan.demo.bean.Cat.eat()

QUERY:

下面这种方法不知道是我测试的问题还是怎么的,有些内容无法获取到,所以还是推荐使用上面的方式。

//导入 * 
import static org.reflections.scanners.Scanners.*;

public class ReflectionTest {

    public static void main(String[] args) {




        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .forPackage("com.qiuguan.demo")
                .filterInputsBy(new FilterBuilder().includePackage("com.qiuguan.demo"))
                .setScanners(TypesAnnotated, MethodsAnnotated, MethodsReturn)
        );




        System.out.println("=================== 获取标注该注解的所有类 =======================");
        Set<Class<?>> typesAnnotatedWith = reflections.get(TypesAnnotated.of(MyAnnotation.class).asClass());
        typesAnnotatedWith.forEach(System.out::println);


        System.out.println("=================== 获取标注该注解的所有方法 =======================");
        Set<Class<?>> methodsAnnotatedWith = reflections.get(MethodsAnnotated.of(MyAnnotation.class).asClass());
        methodsAnnotatedWith.forEach(System.out::println);

        System.out.println("=================== 获取返回值是void的方法 =======================");
        Set<Class<?>> returnsAnnotatedWith = reflections.get(MethodsReturn.of(void.class).asClass());
        returnsAnnotatedWith.forEach(System.out::println);
    }
}
00:14:16.193 [main] INFO org.reflections.Reflections - Reflections took 185 ms to scan 1 urls, producing 10 keys and 19 values
=================== 获取标注该注解的所有类 =======================

class com.qiuguan.demo.bean.Cat

=================== 获取标注该注解的所有方法 =======================
=================== 获取返回值是void的方法 =======================

2. ReflectionUtils

import static org.reflections.ReflectionUtils.*;
//获取某个类的所有父类
Set<Class<?>>    superTypes   = get(SuperTypes.of(T));





//获取所有属性
Set<Field>       fields       = get(Fields.of(T));




//获取所有的构造器
Set<Constructor> constructors = get(Constructors.of(T));




//获取方法
Set<Methods>     methods      = get(Methods.of(T));


//获取资源
Set<URL>         resources    = get(Resources.with(T));

Set<Annotation>  annotations  = get(Annotations.of(T));


Set<Class<? extends Annotation>> annotationTypes = get(AnnotationTypes.of(T));

3. Query API

    QueryFunction<Store, Method> methodQueryFunction = 
     Methods.of(Person.class)  
    .filter(withModifier(Modifier.PUBLIC))  
    .filter(withPrefix("buy").and(withParametersCount(0)))  
    .as(Method.class);
    
    ....

好了,关于 Reflections 工具就介绍到这里,大家可以自己测试看看,我测试的时候发现有几个方法是存在问题的,最后我还是没有在生产环境中使用这个工具。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYcr9fWP' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片