反射实现一个简单spring的bean注入和bean获取的demo

4 篇文章 0 订阅
1 篇文章 0 订阅


前言

为了更好的了解spring注入bean和获取bean的原理。


一、步骤分析

1、将xml文件进行解析
2、生成对象并放进容器中
3、提供获取容器对象的方法getBean(id)

二、maven坐标引入

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
<!--dom4j xml文档解析-->
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>

三、示例代码

1、Person类

package com.example.demo5.testBean;

import lombok.Data;

import java.io.Serializable;

/**
 * @Author lcb
 * @Date 2023/03/19
 **/

@Data
public class Person implements Serializable {

    private Long id;

    private String nickName;

    private Double weight;
}

2、Student类

package com.example.demo5.testBean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @Author lcb
 * @Date 2023/03/19
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {

    private Integer id;

    private String name;

    private Integer age;
}

3、TestBean.xml

<?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 class="com.example.demo5.testBean.Student" id="student">
        <property name="id" value="10"/>
        <property name="name" value="孙悟空"/>
        <property name="age" value="18"/>
    </bean>

    <bean class="com.example.demo5.testBean.Person" id="person">
        <property name="id" value="100"/>
        <property name="nickName" value="孙悟空-呵呵哒"/>
        <property name="weight" value="60.0"/>
    </bean>
</beans>

4、ApplicationContextStudentTest测试类

package com.example.demo5.testBean;

import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.CharUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 实现一个简单的spring容器机制
 * 1、将xml文件进行解析
 * 2、生成对象并放进容器中
 * 3、提供获取容器对象的方法getBean(id)
 *
 * @Author lcb
 * @Date 2023/03/19
 **/
@NoArgsConstructor
@SuppressWarnings("all")
public class ApplicationContextStudentTest {

    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    @SneakyThrows
    public ApplicationContextStudentTest(String pathFile) {
        //1、得到类加载路径
        String path = Objects.requireNonNull(this.getClass().getResource("/")).getPath();
        //2、创建Saxreader对象
        SAXReader saxReader = new SAXReader();
        //3、得到Document对象
        Document document = saxReader.read(new File(path.concat(pathFile)));
        //4、得到rootDocument对象
        Element rootElements = document.getRootElement();
        Class<?> className;
        Object obj;
        //5、获取bean集合对象
        List<Element> rootElementList = (List<Element>) rootElements.elements();
        for (Element rootElement : rootElementList) {
            className = Class.forName(rootElement.attributeValue("class"));
            obj = className.newInstance();
            //6、获取每个对象对应的属性
            for (Element element : (List<Element>) rootElement.elements("property")) {
                List<Attribute> attributes = (List<Attribute>) element.attributes();
                //1)、通过方法设值
                setValueByMethods(className, obj, attributes);
                //2)、通过属性设值
//                setValueByFields(className, obj, attributes);
                //7、将bean对象及其属性信息保存到singletonObjects对象中
                singletonObjects.put(rootElement.attributeValue("id"), obj);
            }
        }
    }

    @SneakyThrows
    private void setValueByFields(Class<?> className, Object obj, List<Attribute> attributes) {
        for (Field field : className.getDeclaredFields()) {
            field.setAccessible(true);
            if (field.getName().equals(attributes.get(0).getValue())) {
                String typeName = field.getGenericType().getTypeName();
                field.set(obj, getFieldValue(typeName, attributes.get(1).getValue()));
            }
        }
    }

    @SneakyThrows
    private void setValueByMethods(Class<?> className, Object obj, List<Attribute> attributes) {
        String attrName = attributes.get(0).getValue();
        for (Method method : className.getDeclaredMethods()) {
            method.setAccessible(true);
            //如果是set属性的方法,就进行属性赋值
            if (method.getName().equals("set".concat(attrName.substring(0, 1).toUpperCase(Locale.ROOT)).concat(attrName.substring(1)))) {
                String typeName = method.getGenericParameterTypes()[0].getTypeName();
                method.invoke(obj, getFieldValue(typeName, attributes.get(1).getValue()));
            }
        }
    }

    /**
     * 根据bean的名称获取bean对象
     *
     * @param beanName bean的名称
     * @return bean对象
     */
    public Object getBean(String beanName) {
        return singletonObjects.get(beanName);
    }

    /**
     * 类型转化
     *
     * @param type  类型
     * @param value 数据
     * @return 将数据转化为对应类型的数据
     */
    @SneakyThrows
    private Object getFieldValue(String type, String value) {
        switch (type.substring(type.lastIndexOf(".") + 1)) {
            case "Byte":
                return Byte.parseByte(value);
            case "Short":
                return Short.parseShort(value);
            case "Character":
                return CharUtils.toChar(value);
            case "Integer":
                return Integer.parseInt(value);
            case "Long":
                return Long.parseLong(value);
            case "Boolean":
                return Boolean.parseBoolean(value);
            case "Float":
                return Float.parseFloat(value);
            case "Double":
                return Double.parseDouble(value);
            default:
                return value;
        }
    }

    public static void main(String[] args) {
        ApplicationContextStudentTest applicationContextStudentTest = new ApplicationContextStudentTest("mapper/TestBean.xml");
        System.out.println(applicationContextStudentTest.getBean("student"));
        System.out.println(applicationContextStudentTest.getBean("person"));
    }
}

四、运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚风岸影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值