首页 > 其他分享 >手写一个简单的IOC容器

手写一个简单的IOC容器

时间:2023-01-14 22:00:13浏览次数:44  
标签:case 容器 java val private 手写 IOC fieldValue


手写一个简单的IOC容器


说明

首先我们都知道,Spring框架中两个最重要的组件就是IOC和AOP。IOC 即 inversion of control 控制反转。Aop即 Aspect Oriented Programming 面向切面编程。那么我们这里就来手写一个简单的IOC容器。这里主要使用 xml配置的方式来实现IOC容器。

前置知识

手撸一个IOC容器需要先掌握好 ​​XML文件解析​​​ 和 ​​Java反射​​知识。

行了,下面我们就开始了。

项目搭建

创建项目

使用普通的maven搭建一个项目。

导入依赖

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>

<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>

实体类

package com.ooyhao.pojo;
import lombok.Data;
import java.io.Serializable;

@Data
public class User implements Serializable {

private byte age;
private Byte ageB;

private short height;
private Short heightS;

private int id;
private Integer idI;

private long weight;
private Long weightL;

private char sex;
private Character sexC;

private float salary;
private Float salaryF;

private double buy;
private Double buyD;

private boolean successB;
private Boolean success;

private String name;
}

spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="user" class="com.ooyhao.pojo.User">
<property name="age" value="2"/>
<property name="ageB" value="20"/>
<property name="height" value="170"/>
<property name="heightS" value="1700"/>
<property name="id" value="1"/>
<property name="idI" value="10"/>
<property name="weight" value="60"/>
<property name="weightL" value="600"/>
<property name="sex" value="m"/>
<property name="sexC" value="f"/>
<property name="salary" value="7500.5"/>
<property name="salaryF" value="9000.5"/>
<property name="buy" value="10.05"/>
<property name="buyD" value="100.5"/>
<property name="success" value="false"/>
<property name="successB" value="true"/>
<property name="name" value="欧阳"/>
</bean>
</beans>

自定义ApplicationContext

/**
* 简单手写一个IOC容器
*/
public class MyApplicationContext implements ApplicationContext {
private static Map<String,Object> beansContainer = new HashMap<>();

public MyApplicationContext(String path){
//构造器中处理
//处理ClassPath下的文件。
ClassPathResource resource = new ClassPathResource(path);
//利用DOM4J解析XML文件
SAXReader reader = new SAXReader();
try {
//读取xml文件,获取到文档
Document document = reader.read(resource.getInputStream());
//根目录beans
Element beansElement = document.getRootElement();
//迭代beans获取多个bean
Iterator<Element> beansIter = beansElement.elementIterator();
while(beansIter.hasNext()){
//单个bean
Element beanElement = beansIter.next();
//id
String id = beanElement.attributeValue("id");
//完整的类名
String className = beanElement.attributeValue("class");
//通过className反射出一个对象
Class<?> aClass = Class.forName(className);
//获取无参数的构造器
Constructor<?> constructor = aClass.getConstructor();
//利用无参数的构造器创建实例
Object o = constructor.newInstance();
//迭代bean获取property
Iterator<Element> beanIter = beanElement.elementIterator();
while (beanIter.hasNext()){
Element property = beanIter.next();
//属性名
String fieldName = property.attributeValue("name");
//属性值
String fieldValue = property.attributeValue("value");
//根据属性名获取属性对象
Field field = aClass.getDeclaredField(fieldName);
//属性的类型
Class<?> fieldType = field.getType();
//拼接set方法名
String setMethodName = "set" + fieldName.substring(0,1).toUpperCase()+ fieldName.substring(1);
//获取方法对象
Method method = aClass.getMethod(setMethodName, fieldType);

Object val = fieldValue;
switch (fieldType.getName()){
case "int":
case "java.lang.Integer":
val = Integer.valueOf(fieldValue);
break;
case "boolean":
case "java.lang.Boolean":
val = Boolean.valueOf(fieldValue);
break;
case "char":
case "java.lang.Character":
val = fieldValue.charAt(0);
break;
case "long":
case "java.lang.Long":
val = Long.valueOf(fieldValue);
break;
case "double":
case "java.lang.Double":
val = Double.valueOf(fieldValue);
break;
case "float":
case "java.lang.Float":
val = Float.valueOf(fieldValue);
break;
case "byte":
case "java.lang.Byte":
val = Byte.valueOf(fieldValue);
break;
case "short":
case "java.lang.Short":
val = Short.valueOf(fieldValue);
break;
}
method.invoke(o,val);
}
beansContainer.put(id,o);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}

public Object getBean(String s) throws BeansException {
Object o = beansContainer.get(s);
return o;
}

public <T> T getBean(Class<T> aClass) throws BeansException {
Collection<Object> values = beansContainer.values();
Iterator<Object> iterator = values.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
if (next.getClass().equals(aClass)) {
return (T) next;
}
}
return null;
}
//部分未实现功能此处省略
}

上述部分就是实现简单的IOC重点内容。主要是基于 XML解析和发射知识。

项目测试

项目测试代码

ApplicationContext context = new MyApplicationContext("spring.xml");
User o = context.getBean(User.class);
System.out.println(JSONObject.toJSONString(o));

测试结果

{
"age": 2,
"ageB": 20,
"buy": 10.05,
"buyD": 100.5,
"height": 170,
"heightS": 1700,
"id": 1,
"idI": 10,
"name": "欧阳",
"salary": 7500.5,
"salaryF": 9000.5,
"sex": "m",
"sexC": "f",
"success": false,
"successB": true,
"weight": 60,
"weightL": 600
}

注意:这里只是实现了一个简单的IOC容器,并且只是实现了 java的简单类型和 包装类型,以及String类型的注入。


标签:case,容器,java,val,private,手写,IOC,fieldValue
From: https://blog.51cto.com/u_12131813/6007939

相关文章

  • Vector 容器类
    Vector底层是用数组实现的,相关的方法都加了同步检查,因此“线程安全,效率低”。比如,indexOf方法就增加了synchronized同步标记。Vector的使用Vector的使用与ArrayL......
  • 获取kubelet管理的容器
    k8s1.15pkg/kubelet/kuberuntime/kuberuntime_container.gogetKubeletContainers方法获取kubelet管理的所有业务容器(true表示包括退出的和死亡的容器,用于GC)补充代码kub......
  • 制作容器镜像的最佳实践
    概述这篇文章主要是我日常工作中的制作镜像的实践,同时结合我学习到的关于镜像制作的相关文章总结出来的.包括通用的容器最佳实践,java,nginx,python容器最佳实践.......
  • Alan的Docker容器学习笔记
    (本文的内容主要来源于Google、百科和学过的一些专栏,目前没有实际的企业级应用容器化部署经验,写的比较浅薄见笑了)为什么会接触到Docker运维同学使用k8s将业务迁移上云时遇到......
  • 49-Docker-网络管理及Compose单机多容器编排
    Docker安装后默认的网络设置Docker服务安装完成之后,默认在每个宿主机会生成一个名称为docker0的网卡其IP地址都是172.17.0.1/16[root@ubuntu2204~]#ipa1:lo:<LOOPBACK,U......
  • 依赖注入-ioc框架
    例子:电脑需要从u盘读取文件 电脑主机读取文件的时候,它一点也不会关心USB接口上连接的是什么外部设备,而且它确实也无须知道。它的任务就是读取USB接口,挂接的外部设备只要......
  • C++ STL容器的Value语义与Reference语义
    C++STL容器的Value语义与Reference语义1.Value语义vs.Reference语义1.1两种语义简述​ 通常情况下,所有容器都是建立元素的copy,返回的元素的copy。因此,容器内的元素与......
  • 使用原子主机、Ansible 和 Cockpit 部署容器
    来自原子项目的原子主机是一个轻量级容器操作系统,可以以Docker格式运行 ​​Linux 容器。它专门为提高效率而定制,使其成为用于云环境的Docker运行时系统的理想选择。......
  • 009排障容器
    一、背景好多业务容器做了裁剪,没法进行基本的调试,所以需要启动一个单独的集成很多排错工具的镜像二、现有方案https://hub.docker.com/r/nicolaka/netshoot(1)k8s......
  • kafka(kraft模式)3.*集群容器部署 docker-compose
    一、创建yml文件要修改部分1.修改宿主机ipKAFKA_CFG_ADVERTISED_LISTENERS2.修改挂载路径version:"3.6"services:kafka1:container_name:kafka1image:......