热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

基于Java反射技术实现简单IOC容器

这篇文章主要介绍了基于Java反射技术实现简单IOC容器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

前言

首先思考一个问题,如果你正在做一个复杂的系统,一个系统模块内有几百个功能业务类,这些类需要使用同一些对象来进行工作。那么,你会怎样去管理这些通用且一样的对象呢?

学习过Spring的朋友会知道,Spring框架为此提供了一种非常先进的思想,即IOC(控制反转)。Spring可以理解为一个工厂,负责对象的创建和对象间关系的维护。IoC即控制反转,简单说就是之前需要使用new的方式创建对象,而Spring框架会从XML文件中根据配置的信息来创建对象,然后放进它自己的容器之中。在程序要使用到该对象的时候,自动注入。

下面就来做一个最简单的IOC容器。

1.创建一个实体类,比如学生类,汽车类

2.创建XML文件配置对象的信息

3.编写一个IOC容器类。这个类工作起来,首先加载XML文件,扫描自己配置的对象信息,之后使用反射技术创建对象,最后将这些

对象放进自己的Map集合中(容器)。外部想要调用这些对象,那么就使用Map的键,来拿到这个集合中对应的值(对象)。

编写一个喜闻乐见的Student学生类。

我做的比较简单,没有使用get() set()方法。

后面使用反射技术可以强制给 private 修饰的属性赋值

package cn.haidnor.bean;

public class Student {
  /** 学生姓名 */
  private String name;
  /** 学生性别 */
  private String gender;
  /** 学生年龄 */
  private int age;
  
  @Override
  public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", gender='" + gender + '\'' +
        ", age=" + age +
        '}';
  }
}

创建XML文件,配置对象信息

  • id 表示在IOC容器(Map)的键
  • class 表示对象类的全类名
  • name 表示对象的各种属性名
  • property下的文本节点表示该属性的值
<&#63;xml version="1.0" encoding="UTF-8"&#63;>

  
    Lucy
    18
    female
  

  
    Tom
    21
    male
  

  
    LiLi
    23
    female
  

编写IOC容器类

1.首先根据XML中的配置文件,生成学生对象

2.所有的对象都放入到一个Map中

3.提供一个getBean()的方法,传入配置文件中的id,返回对应的对象

package cn.haidnor.core;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


public class SpringIOC {

  /**
   * 配置文件地址
   */
  private static final String CONFIGURATION_PATH = "resources/applicationContext.xml";

  /**
   * ioc容器
   */
  private static Map ioc = new HashMap<>();

  static {
    initialization();
  }

  /**
   * 从 ioc 容器中获取指定 bean
   *
   * @param name 需要获取的 bean 的 id, 对应 XML 配置文件中的 bean id
   * @return bean
   */
  public static Object getBean(String name) {
    return ioc.get(name);
  }

  /**
   * 初始化容器
   */
  private static void initialization() {
    Document document = null;

    try {
      DocumentBuilderFactory bdf = DocumentBuilderFactory.newInstance();
      DocumentBuilder documentBuilder = bdf.newDocumentBuilder();
      document = documentBuilder.parse(CONFIGURATION_PATH);
    } catch (Exception e) {
      e.printStackTrace();
    }

    NodeList beanNodes = document.getElementsByTagName("bean");

    for (int i = 0; i  attributeMap = reloadAttribute(childNodes);

    // 使用反射构造 bean 对象
    Object instance = creatBean(beanClass, attributeMap);

    // 将所有的 bean 对象放入容器中
    ioc.put(id, instance);
  }

  /**
   * 加载 bean 的属性值
   *
   * @param attributeNodes 所有的属性 property 节点
   * @return Map 属性的名字和值集合
   */
  private static Map reloadAttribute(NodeList attributeNodes) {
    Map keyValue = new HashMap<>();
    for (int i = 0; i  attributes) {
    Object instance = null;
    try {
      Class<&#63;> clazz = Class.forName(className);
      instance = clazz.newInstance();
      Field[] fields = clazz.getDeclaredFields();

      for (Field field : fields) {
        setFiledValue(instance, field, attributes);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return instance;
  }

  /**
   * 为实例对象的属性赋值
   *
   * @param instance  实例对象
   * @param field   属性字段对象
   * @param attributes 属性名与属性值的 Map 集合
   */
  private static void setFiledValue(Object instance, Field field, Map attributes) {
    // 忽略 field 权限检查
    field.setAccessible(true);

    String type = field.getType().toString();
    String name = field.getName();

    try {
      switch (type) {
        case "char":
          field.setChar(instance, attributes.get(name).charAt(0));
          break;

        case "class java.lang.Boolean":
        case "boolean":
          field.setBoolean(instance, Boolean.parseBoolean(attributes.get(name)));
          break;

        case "class java.lang.Byte":
        case "byte":
          field.setByte(instance, Byte.parseByte(attributes.get(name)));
          break;

        case "class java.lang.Float":
        case "float":
          field.setFloat(instance, Float.parseFloat(attributes.get(name)));
          break;

        case "class java.lang.Integer":
        case "int":
          field.setInt(instance, Integer.parseInt(attributes.get(name)));
          break;

        case "class java.lang.Long":
        case "long":
          field.setLong(instance, Long.parseLong(attributes.get(name)));
          break;

        case "class java.lang.Short":
        case "short":
          field.setShort(instance, Short.parseShort(attributes.get(name)));
          break;

        default:
          field.set(instance, attributes.get(name));
          break;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

最后编写测试类

  • 不使用new的方式创建学生对象
  • 使用ioc容器getBean()方法获取对象
  • 调用对象的复写的toString()方法
package cn.haidnor.test;

import cn.haidnor.bean.Student;
import cn.haidnor.core.SpringIOC;

public class Test {
  public static void main(String[] args) {
    // 不使用 new 的方式创建对象, 从容器中获取
    Student stu1 = (Student) SpringIOC.getBean("stu3");
    // 调用学生类的方法,打印信息
    System.out.println(stu1.toString());
  }
}

运行结果,控制台打印输出的内容

Student{name='LiLi', gender='female', age=23}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 开发笔记:Docker 上安装启动 MySQL
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Docker上安装启动MySQL相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • 乐山市计算机学校2017—2018学年度第一学期开学典礼隆重举行
    乐山市计算机学校于2017—2018学年度第一学期举行了隆重的开学典礼,全体教职工和学生参加了此次典礼。乐山市计算机学校自建校以来一直秉承着追求崇高、抓住机遇、回报社会的办学宗旨,取得了累累硕果。在典礼上,常务副校长梁志明发表了致辞,鼓励全体新生用自己的智慧和勤奋去创造优秀的业绩。同时,苏稽镇派出所所长、市计算机学校法制副校长邹学斌提出了关于遵守法律法规和社会公共道德规范、树立自尊、自律、自强意识以及相信和依靠法律的建议,以维护校园秩序的平安和谐。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文介绍了Java的公式汇总及相关知识,包括定义变量的语法格式、类型转换公式、三元表达式、定义新的实例的格式、引用类型的方法以及数组静态初始化等内容。希望对读者有一定的参考价值。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 本文介绍了一种图片处理应用,通过固定容器来实现缩略图的功能。该方法可以实现等比例缩略、扩容填充和裁剪等操作。详细的实现步骤和代码示例在正文中给出。 ... [详细]
  • C++语言入门:数组的基本知识和应用领域
    本文介绍了C++语言的基本知识和应用领域,包括C++语言与Python语言的区别、C++语言的结构化特点、关键字和控制语句的使用、运算符的种类和表达式的灵活性、各种数据类型的运算以及指针概念的引入。同时,还探讨了C++语言在代码效率方面的优势和与汇编语言的比较。对于想要学习C++语言的初学者来说,本文提供了一个简洁而全面的入门指南。 ... [详细]
  • 本文介绍了Python函数的定义与调用的方法,以及函数的作用,包括增强代码的可读性和重用性。文章详细解释了函数的定义与调用的语法和规则,以及函数的参数和返回值的用法。同时,还介绍了函数返回值的多种情况和多个值的返回方式。通过学习本文,读者可以更好地理解和使用Python函数,提高代码的可读性和重用性。 ... [详细]
author-avatar
欢欢浮夸_704
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有