反射给 Field 赋值,然后调用其方法为何 field 还是为 null?

本贴最后更新于 1493 天前,其中的信息可能已经时移世易

目前在写一个 mvc 框架,IoC 部分自己写的不满意,使用了 Guice,在做整合的时候,因为想实现类似于 SpringBoot 那样开箱即用的方式,所以打算实现两个功能:

  1. 自动扫描
  2. 自动配置

目前出现了问题:

首先有两个 bean 类

@Singleton
public class TestBean {
  private int a =1;
  private int b =1;

  @Override
  public String toString() {
    return "TestBean{" +
            "a=" + a +
            ", b=" + b +
            '}';
  }
}

@Singleton
public class TestBean2 {

  @Inject
  private TestBean testBean;

  public void say() {
    System.out.println(testBean+"111111");
  }
}

然后通过

Injector injector = Guice.createInjector(new AutoScanModule(reflections, scanAnnotationSet));

AutoScanModule 是配置自动扫描的部分,这部分会将标注了 Singleton 注解的类进行扫描,然后将其注册到 Guice 容器中,代码如下:

public class AutoScanModule extends AbstractModule {
  private final Reflections                      packageReflections;
  private final Set<Class<? extends Annotation>> bindingAnnotations;

  public AutoScanModule(Reflections packageReflections, final Set<Class<? extends Annotation>> bindingAnnotations) {
    this.packageReflections = packageReflections;
    this.bindingAnnotations = bindingAnnotations;
  }

  @Override
  public void configure() {
    this.bindingAnnotations.stream()
            .map(getClassSetFunction())
            .flatMap(Set::stream)
            .forEach(this::bind);
  }

  private Function<Class<? extends Annotation>, Set<Class<?>>> getClassSetFunction() {
    return bindingAnnotation -> packageReflections.getTypesAnnotatedWith(bindingAnnotation, true);
  }
}

然后就可以通过如下代码获取装配好的 TestBean2 对象,并且调用 say()方法后,可以看到打印结果,testBean2 也不是 null

Injector injector = Guice.createInjector(new AutoScanModule(reflections, scanAnnotationSet));
Provider<TestBean2> provider1 = injector.getProvider(TestBean2.class);
provider1.get().say();

//TestBean{a=1, b=1}111111 console打印结果

然后我准备做的就是自动装配,也就是不用通过 injector.getProviderinjector.getInstance 的方式来获取,而是
想将标注了 Singleton 注解的类获取到所有的 Field,再根据是否标注了 Inject 注解,然后根据 Field Type 从 Guice 的容器中进行获取后再通过反射赋值

  public void start() throws IllegalAccessException, InstantiationException {
    Injector injector = Guice.createInjector(new AutoScanModule(reflections, scanAnnotationSet));
    for (Class<? extends Annotation> annotationCls : scanAnnotationSet) {
      this.typesAnnotatedWith.addAll(this.reflections.getTypesAnnotatedWith(annotationCls, true));
    }
    for (Class<?> typeClass : typesAnnotatedWith) {
      Field[] fields = typeClass.getDeclaredFields();
      if (fields.length == 0) {
        continue;
      }
      for (Field field : fields) {
        if (field.getAnnotation(javax.inject.Inject.class) != null ||
                field.getAnnotation(com.google.inject.Inject.class) != null) {
          Object type = typeClass.newInstance();
          field.setAccessible(true);
          Provider<?> provider = injector.getProvider(field.getType());//这里从Guice中根据Type拿到
          if (provider != null && provider.get() != null) {
            field.set(type, provider.get());//然后通过反射Set
          }
          System.out.println(field.get(type));
          System.out.println(field);
        }
      }
      if (typeClass.getTypeName().equals(TestBean2.class.getName())){
        TestBean2 testBean2 = (TestBean2) typeClass.newInstance();
        testBean2.say();
      }
    }
  }

打印结果如下:

TestBean{a=1, b=1}
private org.aquiver.bean.TestBean org.aquiver.bean.TestBean2.testBean
null111111

可以看到这两句都不为 null

System.out.println(field.get(type));
System.out.println(field);

但是调用 say 方法的时候,显示为 null111111

TestBean2 testBean2 = (TestBean2) typeClass.newInstance();
testBean2.say();

请问这我测试方式有问题? 还是 newInstance 会重现创建个对象,所以为 null,如果是?那我该换什么方式来做呢?

我通过反射调用 say 方法还是为 field 还是为 null

Method say = typeClass.getMethod("say");
say.invoke(typeClass.newInstance());
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3165 引用 • 8206 回帖
  • Guice
    3 引用 • 5 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6364 引用 • 28621 回帖 • 263 关注
1 操作
Ever 在 2020-02-26 20:51:35 更新了该帖

相关帖子

被采纳的回答
  • Today

    不是一个对象

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • Today

    不是一个对象

推荐标签 标签

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 247 回帖 • 210 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 1 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 7 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    139 引用 • 441 回帖
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    96 引用 • 330 回帖
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    69 引用 • 190 回帖 • 500 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6364 引用 • 28621 回帖 • 263 关注
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 21 关注
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 3 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 31 关注
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    19 引用 • 23 回帖 • 675 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    160 引用 • 470 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 1 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • Chrome

    Chrome 又称 Google 浏览器,是一个由谷歌公司开发的网页浏览器。该浏览器是基于其他开源软件所编写,包括 WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。

    60 引用 • 287 回帖
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    25 引用 • 191 回帖 • 16 关注
  • 分享

    有什么新发现就分享给大家吧!

    240 引用 • 1729 回帖
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 618 关注
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    66 引用 • 124 回帖
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    163 引用 • 529 回帖
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 1 关注
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 686 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 25 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    84 引用 • 139 回帖 • 1 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    51 引用 • 190 回帖