根据源码我们也可以简单的手写一个bean
容器的创建,并解决非AOP
的循环依赖。这里为了方便,不频繁的切换类,这里直接所有写在了一个类里面,只实现了xm
l的setter
注入。
<dependencies>
<dependency>
<groupId>jaxengroupId>
<artifactId>jaxenartifactId>
<version>1.2.0version>
dependency>
<dependency>
<groupId>org.dom4jgroupId>
<artifactId>dom4jartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.19.0version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j2-implartifactId>
<version>2.19.0version>
dependency>
dependencies>
ApplicationContext 接口
package org.myspringframework.core;
/**
* MySpring框架应用上下文接口
**/
public interface ApplicationContext {
/**
* 根据bean的名称获取对应的bean对象
* @param beanName myspring配置文件中bean标签的id
* @return 对应的bean对象
*/
Object getBean(String beanName);
}
ClasspathXmlApplicationContext类。这里我们把所有的方法封装在这个类里面(比如 populateBean)。
package org.myspringframework.core;
import lombok.extern.log4j.Log4j2;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ClasspathXmlApplicationContext implements ApplicationContext {
private Logger log = LoggerFactory.getLogger("ClasspathXmlApplicationContext");
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/**
* 我们假设Object是工厂
*/
private final Map<String, Object> singletonFactories = new HashMap<>(16);
private final Map<String, Element> beanLabel = new HashMap<>(16);
/**
* 解析myspring的配置文件,初始化所有的bean对象
*
* @param configLocation spring配置文件的路径,
* 注意ClasspathXmlApplicationContext,配置文件应当放到类路径下
*/
public ClasspathXmlApplicationContext(String configLocation) {
parse(configLocation);
}
/**
* 解析xml
*
* @param configLocation
*/
private void parse(String configLocation) {
try {
//解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中
//这是dom4j解析XML文件的核心对象
SAXReader saxReader = new SAXReader();
//获取一个输入流,指向配置文件
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);
//读文件
Document document = saxReader.read(in);
//获取所有的bean标签(从任意位置的节点上选择名称为 bean 的节点。)
List<Node> beans = document.selectNodes("//bean");
//先将所有bean标签放入map中
beans.forEach((node) -> {
//System.out.println(node);//rg.dom4j.tree.DefaultElement@1786dec2....
//为了使用更加丰富的方法
Element beanElm = (Element) node;
String beanName = beanElm.attributeValue("id");
beanLabel.put(beanName, beanElm);
});
//遍历map创建对象
beanLabel.forEach((beanName, beanElm) -> {
doGetBean(beanName);
});
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 开始获取bean
*
* @param beanName
* @return
*/
private Object doGetBean(String beanName) {
Element beanElm = beanLabel.get(beanName);
String className = beanElm.attributeValue("class");
log.info("beanName={}", beanName);
log.info("beanClassName={}", className);
//先从缓存中获取bean
Object initInstance = getSingleton(beanName);
if (null == initInstance) {
doCreateBean(beanName);
//创建好了在获取
initInstance = getSingleton(beanName);
}
return initInstance;
}
/**
* 创建bean对象
*
* @param beanName
*/
private void doCreateBean(String beanName) {
Element beanElm = beanLabel.get(beanName);
String className = beanElm.attributeValue("class");
//通过反射机制创建对象,将其放到Map集合,提前曝光
//获取class
try {
Class<?> aClass = null;
aClass = Class.forName(className);
//获取无参数构造方法
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
//调用无参数构造方法实例bean
Object bean = declaredConstructor.newInstance();
//记录日志
log.info("开始创建bean+" + beanName);
//放入到三级缓存
addSingletonFactory(beanName, bean);
//注入属性
populateBean(bean, beanElm);
//在加入到一级缓存
addSingleton(beanName, bean);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 放入到一级缓存
*
* @param beanName
* @param bean
*/
private void addSingleton(String beanName, Object bean) {
singletonObjects.put(beanName, bean);
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
}
/**
* 注入属性
*/
private void populateBean(Object bean, Element beanElm) {
List<Element> properties = beanElm.elements("property");
properties.forEach(property -> {
try {
Class<?> aClass = bean.getClass();
//获取属性名
String propertyName = property.attributeValue("name");
//获取属性类型
Field field = aClass.getDeclaredField(propertyName);
log.info("propertyName: " + propertyName);
//获取set方法名称
String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
//获取set方法
Method setMethod = aClass.getDeclaredMethod(setMethodName, field.getType());
//获取具体的值
String value = property.attributeValue("value");
String ref = property.attributeValue("ref");
if (null != value) {
//说明这个值是简单类型
//调用set方法(set方法没有返回值)
//我们myspring框架声明以下,我们只支持这些8中类型及包装类为简单类型
//获取属性类型
String propertySimpleType = field.getType().getSimpleName();
Object actualValue = null;//真值
switch (propertySimpleType) {
case "byte", "Byte" -> actualValue = Byte.parseByte(value);
case "short", "Short" -> actualValue = Short.parseShort(value);
case "int", "Integer" -> actualValue = Integer.parseInt(value);
case "long", "Long" -> actualValue = Long.parseLong(value);
case "float", "Float" -> actualValue = Float.parseFloat(value);
case "double", "Double" -> actualValue = Double.parseDouble(value);
case "boolean", "Boolean" -> actualValue = Boolean.parseBoolean(value);
case "char", "Character" -> actualValue = value.charAt(0);
case "String" -> actualValue = value;
default -> {
}
}
setMethod.invoke(bean, actualValue);
} else if (null != ref) {
//说明这个值是非简单类型
Object resolveValue = getBean(ref);
//调用set方法(set方法没有返回值)
setMethod.invoke(bean, resolveValue);
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
/**
* 放入到三级缓存
*
* @param beanName
* @param objectFactory 假设bean对象是工厂
*/
public void addSingletonFactory(String beanName, Object objectFactory) {
//将Bean曝光,放入Map集合
singletonFactories.put(beanName, objectFactory);
earlySingletonObjects.remove(beanName);
}
/**
* 从缓存中获取bean
*
* @param beanName
* @return
*/
public Object getSingleton(String beanName) {
Object bean = singletonObjects.get(beanName);
if (null == bean) {
bean = earlySingletonObjects.get(beanName);
if (null == bean) {
bean = singletonFactories.get(beanName);
if (null != bean) {
singletonFactories.remove(beanName);
earlySingletonObjects.put(beanName, bean);
}
}
}
return bean;
}
/**
* 获取bean对象
*
* @param beanName myspring配置文件中bean标签的id
* @return
*/
@Override
public Object getBean(String beanName) {
Object bean = getSingleton(beanName);
if (bean != null) {
return bean;
} else {
doCreateBean(beanName);
return singletonObjects.get(beanName);
}
}
}
A,B,C
@Data
public class A {
private String name;
private B b;
private C c;
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", b=" + b.getName() +
", c=" + c.getName() +
'}';
}
}
@Data
class B {
private C c;
private A a;
private String name;
@Override
public String toString() {
return "B{" +
"c=" + c.getName() +
", a=" + a.getName() +
", name='" + name + '\'' +
'}';
}
}
@Data
class C {
private String name;
private B b;
private A a;
@Override
public String toString() {
return "C{" +
"name='" + name + '\'' +
", b=" + b.getName() +
", a=" + a.getName() +
'}';
}
}
myspring.xml
<beans>
<bean id="a" class="org.myspringframework.core.A">
<property name="name" value="myName is a"/>
<property name="b" ref="b"/>
<property name="c" ref="c"/>
bean>
<bean id="b" class="org.myspringframework.core.B">
<property name="name" value="myName is b"/>
<property name="a" ref="a"/>
<property name="c" ref="c"/>
bean>
<bean id="c" class="org.myspringframework.core.C">
<property name="name" value="myName is c"/>
<property name="a" ref="a"/>
<property name="b" ref="b"/>
bean>
beans>
MyTest
public class MyTest {
@Test
public void testMySpring() {
ApplicationContext applicationContext = new ClasspathXmlApplicationContext("myspring.xml");
A a = (A) applicationContext.getBean("a");
B b = (B) applicationContext.getBean("b");
C c = (C) applicationContext.getBean("c");
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
结果