java 非常好用的反射框架Reflections介绍

Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据。

使用Reflections可以很轻松的获取以下元数据信息:

1)获取某个类型的所有子类;比如,有一个父类是TestInterface,可以获取到TestInterface的所有子类。

2)获取某个注解的所有类型/字段变量,支持注解参数匹配。

3)使用正则表达式获取所有匹配的资源文件

4)获取特定签名方法。

通常的用法有:

引入依赖jar

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

项目中使用:

// 初始化工具类
Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(basePackages).addScanners(new SubTypesScanner()).addScanners(new FieldAnnotationsScanner()));

// 获取某个包下类型注解对应的类
Set<Class<?>> typeClass = reflections.getTypesAnnotatedWith(RpcInterface.class, true);

// 获取子类
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

// 获取注解对应的方法
Set<Method> resources =reflections.getMethodsAnnotatedWith(SomeAnnotation.class);

// 获取注解对应的字段
Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

// 获取特定参数对应的方法
Set<Method> someMethods = reflections.getMethodsMatchParams(long.class, int.class);

Set<Method> voidMethods = reflections.getMethodsReturn(void.class);

Set<Method> pathParamMethods =reflections.getMethodsWithAnyParamAnnotated(PathParam.class);

// 获取资源文件
Set<String> properties = reflections.getResources(Pattern.compile(".*\\.properties"));

具体也可以参见官方文档

补充:Java中的反射:框架设计的灵魂

反射:框架设计的灵魂

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

反射:将类的各个组成部分封装为其他对象,这就是反射机制

好处:

1.可以在程序运行过程中,操作这些对象。

2.可以解耦,提高程序的可扩展性。

获取Class对象的方式:

1.Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象

多用于配置文件,将类名定义在配置文件中。读取文件,加载类

2.类名.class:通过类名的属性class获取

多用于参数的传递

3.对象.getClass():getClass()方法在Object类中定义着。

多用于对象的获取字节码的方式

结论:

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

例如我们有一个Person类

public class Person {
    private String name;
    private int age;
    public Person(){
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

我们写一个Demo用三种方式来获取Class对象

public class Demo1 {
    public static void main(String [] args) throws Exception {
        //1、Class.forName("类名")
        Class cls1 = Class.forName("man.Person");
        System.out.println(cls1);
        //2、类名。class
        Class cls2= Person.class;
        System.out.println(cls2);
        //3、对象.getClass()
        Person p = new Person();
        Class cls3=p.getClass();
        System.out.println(cls3);
    }
}

Class对象功能:

获取功能:

1.获取成员变量们

Field[] getFields() :获取所有public修饰的成员变量

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getDeclaredField(String name)

2.获取构造方法们

Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)
Constructor getDeclaredConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()

3.获取成员方法们:

Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes)

4.获取全类名

String getName() * Field:成员变量

操作:

5.设置值

void set(Object obj, Object value)

6.获取值

get(Object obj)

7.忽略访问权限修饰符的安全检查

setAccessible(true):暴力反射

Constructor:构造方法

创建对象:

T newInstance(Object… initargs)

如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法* Method:方法对象

执行方法:

Object invoke(Object obj, Object… args)

获取方法名称:

String getName:获取方法名

同样对于上面的Person类我们对其新增带参数和不带参数的sleep方法并且写一个Demo来获取这些成员变量,构造方法以及成员方法

Person.java

public class Person {
    private String name;
    private int age;
    public String a;
    protected String b;
    String c;
    private String d;
    public Person(){
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println("eat...");
    }
    public void eat(String food){
        System.out.println("eat..."+food);
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }
}

Demo2.java代码如下:

public class Demo2 {
    public static void main(String [] args) throws Exception {
        Class<Person> personClass = Person.class;
        //获取成员变量
        Field[] fields = personClass.getFields();
        for(Field field:fields) {
            System.out.println(field);
        }
        System.out.println("--------------");
        Field a = personClass.getField("a");//获取a的值
        Person p = new Person();
        Object value=a.get(p);
        System.out.println(value);
        a.set(p, "zhangsan");//设置a的值
        System.out.println(p);
        System.out.println("=============");
        //获取所有成员变量
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        Field d = personClass.getDeclaredField("d");
        d.setAccessible(true);//暴力反射
        Object value2 = d.get(p);
        System.out.println(value2);
        //获取构造方法
        Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
        System.out.println("=======");
        Constructor<Person> constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
        //获取成员方法
        Method eat_method = personClass.getMethod("eat");
        Person p1 = new Person();
        eat_method.invoke(p1);
        Method eat_method1 = personClass.getMethod("eat",String.class);
        eat_method1.invoke(p1,"饭");
        System.out.println("---------");
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

运行结果如下:

public java.lang.String man.Person.a
-------------- null Person{name=‘null', age=0, a=‘zhangsan', b=‘null', c=‘null', d=‘null'}
============= private java.lang.String man.Person.name private int man.Person.age public java.lang.String man.Person.a protected
java.lang.String man.Person.b java.lang.String man.Person.c private
java.lang.String man.Person.d null public
man.Person(java.lang.String,int) Person{name=‘张三', age=23, a=‘null',
b=‘null', c=‘null', d=‘null'}
======= public man.Person() Person{name=‘null', age=0, a=‘null', b=‘null', c=‘null', d=‘null'} eat… eat…饭
--------- public java.lang.String man.Person.toString() public java.lang.String man.Person.getName() public void
man.Person.setName(java.lang.String) public void
man.Person.eat(java.lang.String) public void man.Person.eat() public
void man.Person.setAge(int) public int man.Person.getAge() public
final void java.lang.Object.wait() throws
java.lang.InterruptedException public final void
java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws
java.lang.InterruptedException public boolean
java.lang.Object.equals(java.lang.Object) public native int
java.lang.Object.hashCode() public final native java.lang.Class
java.lang.Object.getClass() public final native void
java.lang.Object.notify() public final native void
java.lang.Object.notifyAll()

案例

需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

实现:

1. 配置文件

2. 反射

步骤:

1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中

2. 在程序中加载读取配置文件

3. 使用反射技术来加载类文件进内存

4. 创建对象

5. 执行方法

为了实现创建任意类的对象,并且执行其中任意方法,我们再原有Person.java文件基础上新增Student.java,代码如下:

public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}

那么我们需要在src目录下添加pro.properties文件并写入以下配置信息

className=man.Student
methodName=sleep

接着我们来写这个案例ReflectTest.java,代码如下

public class ReflectTest {
    public static void main(String [] args) throws Exception {
        //加载配置文件
        Properties pro = new Properties();
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);
        //获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //加载该类进内存
        Class cls = Class.forName(className);
        Object obj = cls.newInstance();
        Method method = cls.getMethod(methodName);
        method.invoke(obj);
    }
}

这样我们只需改变配置文件中的信息而不需要去改变任何代码就可以实现类以及类中的方法​,整个目录结构如下

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 手把手教你从零设计一个java日志框架

    输出内容 - LoggingEvent 提到日志框架,最容易想到的核心功能,那就是输出日志了.那么对于一行日志内容来说,应该至少包含以下几个信息: 日志时间戳 线程信息 日志名称(一般是全类名) 日志级别 日志主体(需要输出的内容,比如info(str)) 为了方便的管理输出内容,现在需要创建一个输出内容的类来封装这些信息: public class LoggingEvent { public long timestamp;//日志时间戳 private int level;//日志级别 pri

  • Java爬虫框架之WebMagic实战

    一.介绍 WebMagic是一个简单灵活的Java爬虫框架.基于WebMagic,你可以快速开发出一个高效.易维护的爬虫. 二.如何学习 1.查看官网 官网地址为:http://webmagic.io/ 官网详细文档:http://webmagic.io/docs/zh/ 2.跑通hello world示例(具体可以参考官网,也可以参考博客) 我下面写的单元测试案例,可作为Hello World示例. 注意需要导入Maven依赖: <dependency> <groupId>us.

  • Java高并发测试框架JCStress详解

    前言 如果要研究高并发,一般会借助高并发工具来进行测试.JCStress(Java Concurrency Stress)它是OpenJDK中的一个高并发测试工具,它可以帮助我们研究在高并发场景下JVM,类库以及硬件等状况. JCStress学起来很简单,而且官方也提供了许多高并发场景下的测试用例,只要引入一个jar包,即可运行研究. 如何使用JCStress 此演示用maven工程,首先需要引入jar包,核心包是必须要的,样例包非必须要,此是为了演示其中的例子. <dependencies>

  • Java中JFinal框架动态切换数据库的方法

    需求:需要根据企业ID切换对应的数据库,同时,后期可动态增加数据库配置 JFinal框架中对于对于多数据源配置有两种方式: 1.通过配置文件配置,有多少数据库就要配置多少,服务启动时加载所有数据库,缺点:不能动态增加数据库 2.只配置一个主数据库信息就可以了,其他数据库信息保存在表中,通过读取表数据加载数据库连接,优点:在数据表中增加数据库配置即可动态增加数据库连接. 本次主要介绍第2种方法: 一.新建数据表:保存数据库连接信息 配置表对应的实体类 public class DbDto { /*

  • Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)

    Shiro简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理 三个核心组件:Subject, SecurityManager 和 Realms Subject代表了当前用户的安全操作 SecurityManager管理所有用户的安全操作,是Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务. Realm充当了Shiro与应用安全数据间的"桥梁"或者"连接器&q

  • java mybatis框架配置详解

    一个框架的使用,必然离不开其中的组件支持.我们在下载完mybatis框架后,因为大部分的内部结构还没有启动,就要手动的对其进行配置.在之前有提到,mybatis框架的作用就有数据库方面的,所以本篇文章带来了数据库和sql方面的配置方法,大家一起往下面看看具体操作. 1.配置数据库 创建mybatis的配置文件,配置数据库的信息.数据库我们可以配置多个,但是默认的只能用一个. <?xml version="1.0" encoding="UTF-8"?> &

  • 使用JAVA+Maven+TestNG框架实现超详细Appium测试安卓真机教程

    前言:前段时间做了selenium的学习和实践,有点意犹未尽,所以自己就又学了下Appium的使用,因为这一套东西在16年已经停止维护了,不管实现还是设计上都不是很容易,也踩了很多坑,现在在此记录下大概过程.后续有时间再完善手册. 一.准备 安装SDK,配置环境变量 链接: https://pan.baidu.com/s/1g2QaWjdfg6Txa0gZf9kk3A 提取码: 8aaz windows配置环境SDK变量 我的电脑右键->属性 点击高级系统设置 点击环境变量 点击新建按钮,变量名

  • 分享我的第一次java Selenium自动化测试框架开发过程

    由于公司的开发团队偏向于使用Java技术,而且公司倡导学习开源技术,所以我选择用Java语言来进行Selenium WebDriver的自动化框架开发.由于本人没有Java开发经验,以前虽然学过QTP但从没有接触过Selenium,正好通过这个机会能学习一下自动化测试,同时也学习一下基本的Java开发过程. 一.首先是搭建框架开发环境 按照网上的方法部署eclipse,建立TestAction工程,并Import引用JDK和Selenium-2.44完整包 二.继续引用和安装相关jar包 1.首

  • Micronaut框架的简单使用介绍

    什么是Micronaut Micronaut是一个基于JVM的框架,用于构建轻量级.模块化的应用程序.Micronaut是由创建Grails的同一家公司OCI开发的最新框架,旨在使创建微服务变得快速和简单. 虽然Micronaut包含一些类似于Spring等现有框架的特性,但它也有一些新特性使它与众不同.通过对Java.Groovy和Kotlin的支持,它提供了多种创建应用程序的方法. 主要特点 Micronaut最令人兴奋的特性之一是它的编译时依赖注入机制.大多数框架使用反射和代理在运行时执行

  • java swing框架实现贪吃蛇游戏

    本文实例为大家分享了java swing实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下 1.编写main方法 package game; import java.awt.Graphics; import javax.swing.*; public class snakeMain extends JFrame { public snakeMain() { snakeWin win = new snakeWin(); add(win); setTitle("̰贪吃蛇v1.0"); se

随机推荐