【第10章】手写spring-ioc之xml版


前言

我们将通过一个简单的案例,手写spring读取配置创建容器并注入依赖。


一、准备

1. service

1.1 service

package org.example.xml.service;

/**
 * Create by zjg on 2024/4/6
 */
public interface UserService {
    public void addUser();
}

1.2 impl

package org.example.xml.service.impl;

import org.example.xml.dao.UserDao;
import org.example.xml.service.UserService;

/**
 * Create by zjg on 2024/4/6
 */
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    private String store;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setStore(String store) {
        this.store = store;
    }

    @Override
    public void addUser() {
        System.out.println("UserServiceImpl..");
        userDao.addUser();
        System.out.println("store:"+store);
    }

}

2. dao

2.1 dao

package org.example.xml.dao;

/**
 * Create by zjg on 2024/4/6
 */
public interface UserDao {
    public void addUser();
}

2.2 impl

package org.example.xml.dao.impl;

import org.example.xml.dao.UserDao;

/**
 * Create by zjg on 2024/4/6
 */
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("UserDaoImpl..");
    }
}

二、核心代码

1.引入库

使用dom4j来解析xml配置文件

<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
<dependency>
     <groupId>org.dom4j</groupId>
     <artifactId>dom4j</artifactId>
     <version>2.1.3</version>
 </dependency>

2.核心代码

2.1 BeanDefinition

记录bean对象的信息

package org.example.xml.context;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * Create by zjg on 2024/4/13
 */
public class BeanDefinition {
    private String id;
    private String clazz;
    private Object instance;
    private Map<String,String> dependencyMap;

    public BeanDefinition(String id, String clazz, Object instance) {
        this.id = id;
        this.clazz = clazz;
        this.instance = instance;
        this.dependencyMap=new HashMap<>();
    }
    public boolean add(String key,String value){
        if("null".equals(dependencyMap.put(key, value))){
            return true;
        }
        return false;
    }

    public void setField(String name,Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = instance.getClass().getDeclaredField(name);
        if(!field.canAccess(instance)){
            field.setAccessible(true);
        }
        field.set(instance,value);
    }

    public Map<String, String> getDependencyMap() {
        return dependencyMap;
    }

    public Object getInstance() {
        return instance;
    }
}

2.2 ClassPathXmlApplicationContext

上下文类负责加载配置文件和bean对象

package org.example.xml.context;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.BeansException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Create by zjg on 2024/4/13
 */
public class ClassPathXmlApplicationContext {
    private String configLocation;
    private volatile List<String> beanDefinitionNames;
    private final Map<String, BeanDefinition> beanDefinitionMap;

    public ClassPathXmlApplicationContext(String configLocation) throws IOException, DocumentException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        this.configLocation = configLocation;
        this.beanDefinitionNames=new ArrayList<>();
        this.beanDefinitionMap = new ConcurrentHashMap(128);
        loadFile();
        dependencyInjection();
    }

    private void loadFile() throws IOException, DocumentException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader().getResources(this.configLocation);
        while (enumeration.hasMoreElements()){
            URL url = enumeration.nextElement();
            File file = new File(URLDecoder.decode(url.getFile(), "utf-8"));
            reader(file);
        }
    }
    private void reader(File file) throws IOException, DocumentException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
        StringBuilder sb=new StringBuilder();
        String str ;
        while ((str=bufferedReader.readLine())!=null){
            sb.append(str);
        }
        loadBeans(sb.toString());
    }
    private void loadBeans(String config) throws DocumentException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Document document = DocumentHelper.parseText(config);
        List<Element> elementList = document.getRootElement().elements("bean");
        for (Element element:elementList){
            String id = element.attribute("id").getValue();
            String clazz=element.attribute("class").getValue();
            Class<?> clz = Class.forName(clazz);
            Object instance = clz.getDeclaredConstructor().newInstance();
            BeanDefinition beanDefinition = new BeanDefinition(id, clazz, instance);
            this.beanDefinitionNames.add(id);
            this.beanDefinitionMap.put(id,beanDefinition);
            injection(element,beanDefinition);
        }
    }
    private void injection(Element element1,BeanDefinition beanDefinition) throws NoSuchFieldException, IllegalAccessException {
        List<Element> elementList = element1.elements("property");
        for (Element element:elementList){
            String name = element.attribute("name").getValue();
            Attribute value = element.attribute("value");
            Attribute ref = element.attribute("ref");
            if(value!=null){
                beanDefinition.setField(name,value.getValue());
            }else if(ref!=null){
                beanDefinition.add(name,ref.getValue());
            }
        }
    }
    private void dependencyInjection() throws NoSuchFieldException, IllegalAccessException {
        Iterator<BeanDefinition> iterator = this.beanDefinitionMap.values().iterator();
        while (iterator.hasNext()){
            BeanDefinition beanDefinition = iterator.next();
            Map<String, String> dependencyMap = beanDefinition.getDependencyMap();
            Iterator<Map.Entry<String, String>> iterator1 = dependencyMap.entrySet().iterator();
            while (iterator1.hasNext()){
                Map.Entry<String, String> dependency = iterator1.next();
                String key = dependency.getKey();
                String value = dependency.getValue();
                beanDefinition.setField(key,this.beanDefinitionMap.get(value).getInstance());
            }
        }
    }
    public List<String> getBeanDefinitionNames(){
        return this.beanDefinitionNames;
    }
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T)this.beanDefinitionMap.get(name).getInstance();
    }
}

2.3 测试类

package org.example;

import org.example.annotation.context.AnnotationApplicationContext;
import org.example.xml.context.ClassPathXmlApplicationContext;

/**
 * Create by zjg on 2024/4/6
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
        xml();
    }
    public static void xml(){
        try {
            ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("springContext.xml");
            classPathXmlApplicationContext.getBean("userService",org.example.xml.service.UserService.class).addUser();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2.4 测试结果

Hello world!
UserServiceImpl..
UserDaoImpl..
store:YES

总结

回到顶部

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值