在这里简单的实现一下spring容器对对象的的存入和取出
首先要下载几个必备的jar包,地址如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
建立一个Factory的接口对应的是spring中的BeanFactory接口
package spring;
public interface BeanFactoryDemo {
Object getBean(String objName); //对应的是BeanFactory中从容器获取对象的方法,其有三种重载方式
<T> T getBean(String objName,Class<T> type);
<T> T getBean(Class<T> type);
}
Factory的实现类即对应spring中根据xml创建对象并为对象赋值和获取对象的类:
package spring;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.table.DefaultTableColumnModel;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ClassPathXMLApplicationContextDemo implements BeanFactoryDemo{
private static final String DEFULT_XML_NAME="demo.xml";
private String xmlName;
private Map<String,Node> map=new HashMap<>();
//这个map即代表spring容器,键值为对象名,值的值为内部类Node的对象,Node包含了这个对象及其这个对象在xml中对应的节点,因为map的键值唯一,所以也间接实现了单例
/*
* 加载配置文件
*/
public ClassPathXMLApplicationContextDemo(String xmlName) throws Exception { //构造器
this.xmlName=xmlName; //当有参数时,将xml设置为指定xml
loader();
}
public ClassPathXMLApplicationContextDemo() throws Exception { //构造器
this.xmlName=DEFULT_XML_NAME; //设置xml为默认xml文件
loader();
}
public void loader() throws Exception{ //实现底层的一些处理,并创建xml中的所有对象并将其放入map
//获取一个xml的输入流
InputStream in=ClassPathXMLApplicationContextDemo.class.getClassLoader().getResourceAsStream(xmlName);
SAXReader reader=new SAXReader(); //新建一个reader对象
Document doc=reader.read(in); //创建一个文档对象 使用reader读取流中的内容
Element root=doc.getRootElement(); //获取根结点
List<Element> childrens=root.elements(); //获取根结点的子节点即所有的对象节点
for (Element e : childrens) { //遍历所有xml中对象的节点
String objName=e.attributeValue("id"); //获取对象点的id属性的值
String classPath=e.attributeValue("class"); //获取class属性值
Class c=Class.forName(classPath); //利用反射得到类
Object obj=c.newInstance(); //通过反射创建对象
Node node=new Node(obj,e); //将新建的对象和其在xml中对应的节点一起封装成一个Node对象
map.put(objName,node); //将生成的Node对象放入spring容器,以待使用
setAttributes(); //调用赋值函数,为容器中的对象赋值
}
}
private void setAttributes() throws Exception{ //给对象赋值
Collection<Node> list=map.values(); //获取到map中的所有值的值放入一个Node类型的list
for (Node node : list) { //遍历值的list
Object obj=node.getObj(); //获取到真正的对象,准备为其赋值
Element e=node.getE(); //获取到对象在xml中对应的节点
Class c=obj.getClass(); //根据对象获取对象的类型
List<Element> echildrens=e.elements(); //获取对象节点的所有子节点,即为属性赋值的节点,并将其放入一个list
if(echildrens.size()>0) { //判断list是否为空
for (Element ec : echildrens) { //遍历bean的子节点(),即赋值节点
String attributeName=ec.attributeValue("name"); //获取此属性的值,对应的是封装类中的属性名称
String attributeValue=ec.attributeValue("value");
String attributeRef=ec.attributeValue("ref");
//获取set方法
String methodName="set"+attributeName.substring(0, 1).toUpperCase()+attributeName.substring(1) ;
Field field=c.getDeclaredField(attributeName);
Class fieldType=field.getType();
Method method=c.getMethod(methodName, new Class[] {fieldType});
if(attributeValue!=null) {
method.invoke(obj, new Object[] {typeHandler(attributeValue,fieldType)});//执行获取到的set方法,在传参时调用了类型处理器
}else if(attributeRef!=null) {
Object refObj=map.get(attributeRef).getObj();
method.invoke(obj, new Object[] {refObj});
}
}
}
}
}
private Object typeHandler(String value,Class t) { //类型处理器
Object obj=null;
String n1=t.getName();
if(n1.equals(Integer.class.getName())) {
obj=Integer.parseInt(value);
}else if(n1.equals(Character.class.getName())) {
obj=value.charAt(0);
}else if(n1.equals(Double.class.getName())) {
obj=Double.parseDouble(value);
}else if(n1.equals(String.class.getName())) {
obj=value;
}
return obj;
}
@Override
public Object getBean(String objName) { //从容器中获取对象
Object obj=map.get(objName).getObj();
return obj;
}
@Override
public <T> T getBean(String objName, Class<T> type) { //从容器中获取对象(重载)
Object obj=map.get(objName).getObj();
return (T)obj;
}
@Override
public <T> T getBean(Class<T> type) { //从容器中获取对象(重载)
Object obj=null;
String className=type.getName(); //得到完整类路径
Collection<Node> list=map.values();
for (Node obj1 : list) {
if(obj1.getClass().getName().equals(className)) {
obj=obj1.getObj();
}
}
return (T)obj;
}
private class Node{ //内部类:将Object和类型进行封装
private Object obj;
private Element e;
public Node(Object obj,Element e) {
this.obj=obj;
this.e=e;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Element getE() {
return e;
}
public void setE(Element e) {
this.e = e;
}
}
}
现在就可以测试这个简易版本的spring了:
首先书写封装类:
package spring;
public class A {
public String name;
public Integer id;
public A() {
System.out.println("创建了A的对象!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "A [name=" + name + ", id=" + id + "]";
}
}
package spring;
public class B {
public B() {
System.out.println("创建了B的对象!");
}
}
package spring;
public class C {
private A a;
private B b;
public C() {
System.out.println("创建了C的对象!");
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
@Override
public String toString() {
return "C [a=" + a + ", b=" + b + "]";
}
}
书写xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="a1" class="spring.A" >
<property name="id" value="111"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="b" class="spring.B" />
<bean id="a2" class="spring.A" />
<bean id="c" class="spring.C">
<property name="a" ref="a1"></property>
<property name="b" ref="b"></property>
</bean>
</beans>
测试类的书写:
package spring;
public class Test {
public static void main(String[] args){
try {
BeanFactoryDemo demo=new ClassPathXMLApplicationContextDemo("applicationContext.xml");
System.out.println(demo.getBean("c"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其输出结果为: