Spring深度分析IoC/DI机制 配置文件式 基本实现
Posted 在下右转,有何贵干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring深度分析IoC/DI机制 配置文件式 基本实现相关的知识,希望对你有一定的参考价值。
首先,本人来提供一个 容器接口:
容器接口 —— ApplicationContext接口:
package edu.youzg.simulate_IoC.bean;
public interface ApplicationContext {
public Object getBean(String beanId);
}
现在,本人来给出这个接口的实现类:
容器接口实现类 —— ClassPathXmlApplicationContext类:
package edu.youzg.simulate_IoC.bean;
import edu.youzg.simulate_IoC.entity.BeanDefinition;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ClassPathXmlApplicationContext implements ApplicationContext {
//以id为键,相应的BeanDefinition为值,封装从xml配置文件中所需读取到的的信息
private static Map<String, BeanDefinition> xmlBeans = new HashMap<String, BeanDefinition>();
//IOC容器,以id为键,对象为值,封装new出来的信息,以便我们进行“依赖注入”工作
private static Map<String, Object> beanIoc = new HashMap<String, Object>();
/**
* 加载配置文件路劲,配置文件是一个xml文件
*
* @param path 配置文件的路径
*/
public ClassPathXmlApplicationContext(String path) {
try {
//解析xml文件
//SAXReader:可以类比是一个管道,用流的方式,把xml文件读出来
SAXReader reader = new SAXReader();
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("beans.xml");
//获取 整个文档对象
Document document = reader.read(inputStream);
//将 根节点 封装为 一个Element对象
Element rootElement = document.getRootElement();
//遍历子节点
List<Element> beanList = rootElement.elements();
//读取bean配置的时候,需要读取到 id、class、init、destory、autowire....等属性
//将bean节点属性,以及 子节点“集合” 封装起来
for (Element bean : beanList) {
//封装bean
BeanDefinition beanDefinition = new BeanDefinition();
//取得bean元素的属性 属性被封装为 Attribute对象
Attribute idatt = bean.attribute("id");
Attribute classatt = bean.attribute("class");
Attribute initatt = null;
try {
initatt = bean.attribute("init");
} catch (Exception e) {
}
Attribute scopeatt = null;
try {
scopeatt = bean.attribute("scope");
} catch (Exception e) {
e.printStackTrace();
}
String idVal = idatt.getValue();
String classVal = classatt.getValue();
beanDefinition.setId(idVal);
beanDefinition.setClasspath(classVal);
String value = null;
try {
value = initatt.getValue();
} catch (Exception e) {
}
String scope = null;
try {
scope = scopeatt.getValue();
} catch (Exception e) {
}
beanDefinition.setInit(value);
beanDefinition.setScope(scope);
//储存起来
xmlBeans.put(idVal, beanDefinition);
}
/*System.out.println("解析xmlbean完成,解析的结果为:");
System.out.println(" " + JSON.toJSONString(xmlBeans, true));*/
//对xmlBeans进行java的解析,解析为实际的xml中配置的java对象
Set<String> keys = xmlBeans.keySet();
for (String key : keys) {
Object obj = newInstance(key);
//将id和obj对应的储存储到IOC容器中,以便我们之后获取使用
beanIoc.put(key, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String beanId) {
//首先获取beanId对应的 scope配置信息
BeanDefinition beanDefinition = xmlBeans.get(beanId);
if (beanDefinition == null) {
throw new RuntimeException("[Youzg Error]:
索引[" + beanId + "]不存在!");
}
Object result = null;
//获知 “单例性”,默认为 单例模式
String scope = beanDefinition.getScope();
if (null!=scope && scope.equals("propotype")) {
result = newInstance(beanDefinition.getId());
return result;
} else if (scope.equals("singleton") || null==scope) {
result = beanIoc.get(beanId);
if (result == null) {
throw new RuntimeException("[Youzg Error]:
IoC容器中不存在[" + beanId + "]的对象");
}
return result;
} else {
throw new RuntimeException("[Youzg Error]:
scope属性值[" + scope + "]无法识别!");
}
}
//通过反射机制,创建Java对象
private Object newInstance(String beanId) {
Object obj = null;
try {
BeanDefinition beanDefinition = xmlBeans.get(beanId);
//需要对xml解析后的java对象BeanDefinition 进行加工【将配置变为java对象】 还要存放在IOC容器中
String classPath = beanDefinition.getClasspath();
//加载这个类
Class cls = Class.forName(classPath);
//创建类的对象
obj = cls.newInstance();
//判断有没有配置生命周期
if (beanDefinition.getInit() != null && !beanDefinition.getInit().equals("")) {
//配置的初始化方法名称
String initMethod = beanDefinition.getInit();
//此刻调用obj的initMethod方法
Method method = cls.getDeclaredMethod(initMethod);
method.invoke(obj);//执行方法
}
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
接下来,本人再来给出一个 用于封装xml文件中 每一个bean节点信息 的BeanDefinition类:
封装节点信息 —— BeanDefinition类:
package edu.youzg.simulate_IoC.entity;
/**
* 用于封装xml文件中 每一个bean节点信息
*/
public class BeanDefinition {
private String id;
private String classpath;
private String init;
private String scope;
public String getInit() {
return init;
}
public void setInit(String init) {
this.init = init;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
}
那么,通过上述的接口与类,我们就基本实现了配置文件式的IoC/DI机制
测试:
现在,本人来提供一个测试类 以及 一个测试配置文件来测试下我们上面的代码是否复合要求:
首先是一个 要被自动注入的类:
package edu.youzg.simulate_IoC.test;
public class AccountService {
public AccountService() {
System.out.println("目标类的 构造方法");
}
public void sayHello() {
System.out.println("hello xml IoC!");
}
public void doSomething() {
System.out.println("目标类的 某方法");
}
}
接下来是配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans id="nihao" class="">
<!--将service交给 自定义的IOC容器-->
<bean id="accountService" class="edu.youzg.simulate_IoC.test.AccountService" scope="singleton"></bean>
</beans>
那么,现在本人最后再来给出一个Demo类:
package edu.youzg.simulate_IoC.test;
import edu.youzg.simulate_IoC.bean.ApplicationContext;
import edu.youzg.simulate_IoC.bean.ClassPathXmlApplicationContext;
/**
* @Author: Youzg
* @CreateTime: 2020-04-26 00:35
* @Description:带你深究Java的本质!
*/
public class Demo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
AccountService service1 = (AccountService) context.getBean("accountService");
AccountService service2 = (AccountService) context.getBean("accountService");
service1.sayHello();
System.out.println(service1 == service2);
}
}
现在,本人来展示下运行结果:
那么,可以看到,我们基本实现了IoC/DI机制!
接下来我们只需要处理一下子标签的注入就ok了
以上是关于Spring深度分析IoC/DI机制 配置文件式 基本实现的主要内容,如果未能解决你的问题,请参考以下文章
Spring 框架的概述以及Spring中基于XML的IOC配置