文章目录
前言
我们将通过一个简单的案例,手写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