手写简易版SpringIOC

     SpringIOC就不在介绍了的吧,对容器创建,管理对象的过程非常有必要自己熟悉了解一下其中的生产规程。手写一个简易版的吧。(BeanFactory,ApplicationContext的,FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,

AnnotationConfigApplicationContext
Spring的各个模块构建的核心模块之上,Bean包装的是Object对象,Object里面一定是存在数据的,Context给数据提供一个生存空间的,Context就是发现和维护Bean之间的关系的,这个复杂的Bean的关系集合可以说是SpringIOC容器.)

    环境搭建:IDEA,Java8,搭建Maven工程。工程图如下,需要依赖jar包的,如果感觉找jar包比较麻烦的,就使用Maven的Java工程吧,绘制采用百度脑图。

   手写简易版的SpringIOC步骤如下,本次实现过程基于如下的步骤的.

  


依赖的POM文件如下:

 <dependency>
  <! -  jdom依赖 - >
  <dependency>
          <groupId> org.jdom </ groupId>
          <artifactId> jdom </ artifactId>
          <version> 2.0.2 </ version>
      </ dependency>
  <! -  jaxen解析依赖 - >
  <dependency>
          <groupId> jaxen </ groupId>
          <artifactId> jaxen </ artifactId>
          <version> 1.1.6 </ version>
      </ dependency>
  </ dependencies> 

这个以一个学生类为依赖注入的案例.

Student

public class Student {
    private String name;
    private String grade;
    private String major;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    /** 自我介绍的方法*/
    public void introduce(){
        System.out.println("我是叫"+name+",是一名"+major+"专业的"+grade+"学生!");
    }
}

StudentService

扫描二维码关注公众号,回复: 857315 查看本文章

public class StudentService {
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }
}

ApplicationContext

public interface ApplicationContext {
    Object getBean(String name);
}

ClassPathXmlApplicationContext(注意观察导包)

import com.lx.spring.myioc.iocfactory.ApplicationContext;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPath;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
 * title: com.lx.spring.myioc.iocfactory.impl
 * @author: 
 * date: 
 * description:基于类路径加载配置文件
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {
    /** 要解析的配置文件*/
    private File file;
    /** 存放Bean对象的实例*/
    private Map map=new HashMap();
    /** 解析配置文件,实例化容器,将对象存放入容器当中*/
    public ClassPathXmlApplicationContext(String configfile) throws Exception {
       URL url =this.getClass().getClassLoader().getResource(configfile);
        try {
            file=new File(url.toURI());
            xmlParse(file);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
    /**
     * 解析xml文件
     * @param file
     */
    private void xmlParse(File file) throws JDOMException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        SAXBuilder builder=new SAXBuilder();
        Document document=builder.build(file);
        // 创建XPath对象,反射获取XPath对象
        XPathFactory factory = XPathFactory.instance();
        // 获取所有的Bean节点,XPath解析写的写法可以了解一下
        XPathExpression expression=factory.compile("//bean");
        // 注释了旧版本的写法获取所有的Bean节点
        // XPath xPath=XPath.newInstance("//bean");
        //List beans=xPath.selectNodes(document);
        List beans=expression.evaluate(document);
        Iterator iterator=beans.iterator();
        while(iterator.hasNext()){
            Element bean=(Element) iterator.next();
            // 获取配置文件的id属性值  
            String id=bean.getAttributeValue("id");
            String cls=bean.getAttributeValue("class");
            // 反射拿到类的相应信息,首先是拿到类的实例对象
            Class clazz=Class.forName(cls);
            Object object=clazz.newInstance();
            // 获取类的所有方法,然后通过set方法给这个对象设置属性值
            Method[] methods=clazz.getDeclaredMethods();
            // 遍历Bean节点下的所有属性和方法,一一匹配,反射设置对象的属性值
            List<Element> list=bean.getChildren("property");
            for(Element element:list){
                for(int i=0;i<methods.length;i++){
                   String methodName=methods[i].getName();
                   // 属性名
                   String temp="";
                   // 这里检索set方法 
                   if(methodName.startsWith("set")){
                   // 这里就只截取set方法的方法名并且转换为小写的名字
                      temp=methodName.substring(3).toLowerCase();
                       // 属性为普通对象的属性
                       if(element.getAttribute("name")!=null){
                           if(temp.equals(element.getAttributeValue("name"))){
                               // 反射给对象设置值
                               methods[i].invoke(object,element.getAttributeValue("value"));

                           }
                       }else{ // 属性为引用对象的属性
                               methods[i].invoke(object,map.get(element.getAttributeValue("ref")));
                       }
                   }
                }
            }
            // 将对象添加到容器里面
            map.put(id,object);
        }
    }
    /** 获取Bean对象*/
    public Object getBean(String name) {
        return map.get(name);
    }
}

application.xml文件如下.

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="Student" class="com.lx.spring.myioc.pojo.Student">
        <property name="name" value="Tom" />
        <property name="grade" value="大三" />
        <property name="major" value="计算机科学与技术" />
    </bean>
    <bean id="StudentService" class="com.lx.spring.myioc.service.StudentService">
        <property ref="Student" />
    </bean>
</beans>

测试一下:MyIocTest.(这里根据类路径下的配置文件)

import com.lx.spring.myioc.iocfactory.impl.ClassPathXmlApplicationContext;
import com.lx.spring.myioc.service.StudentService;
/**
 * title: com.lx.spring.myioc.test
 * @author: 
 * date: 
 * description:测试
 */
public class MyIocTest {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        StudentService student=(StudentService)context.getBean("StudentService");
        student.getStudent().introduce();
    }
}

运行结果:(和调用相应的introduce的方法结果是一样的.)


原理注释部分已写的非常清晰了的,SpringIOC的三种注入方式这里以Set方法注入的进行介绍的.

总结一句话:Java通过配置文件的解读,反射拿到类实例,获取该类的所有Set方法,过滤取出和Xml中配置的属性值,然后反射动态给该属性设置(Xml中配置的值),这样调用相应属性的get方法就可以获取到相应的值啦.



猜你喜欢

转载自blog.csdn.net/HcJsJqJSSM/article/details/80302655