• 自己动手写spring容器(1)


         毕业刚刚一年多一点,毕业了后也顺利的进入了一家著名的互联网公司,做的是后台系统,用的呢也是SSI(struts2,spring)框架,平时做做项目,也已足够了,但是感觉越来越没动力了,越来越没有激情了,就像我们的老大说的,"天天接Task,有意思?,有时间不知道把框架的源码看看!",最近加班相对较少,闲下来就来摸索一下spring。

    写这篇文章只是想让大家了解一下Spring到底是怎么运行的,并不是想重造噢,希望大家看完这篇文章后能对Spring有更深入的了解,对初学者有所帮助喔!好,言归正传,让我们来一起探索吧!

     我们先开看看spring是怎么运行的。。

    1  //读取配置文件实例化一个IoC容器
    2         ApplicationContext ctx=new ClassPathXmlApplicationContext("resources/beans.xml");
    3          //从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
    4          PersonService personService=(PersonService) ctx.getBean("personService",PersonService.class);
    5          personService.sayHello();

    我们来分析一下,首先是加载spring的配置文件,此处是beans.xml

    1     <bean id="personService" class="com.yangyang.service.impl.PersonServiceImpl">
    2     </bean>

    然后是通过调用getBean方法来获取并实例化personService对象,最后是调用sayHello方法

    那么spring到底是如何做到的呢?很明显,第一步肯定是要解析bean.xml文件,

    为此我们写一个自己的ClassPathXmlApplicationContext类来模拟spring的行为,,此处加入一个参数为string类型的构造函数,用来读取配置文件及模拟spring以后的行为,

     1 package com.juit;
     2 
     3 public class YhdClassPathXmlApplicationContext {
     4     /**
     5      * 构造方法,用来模拟spring的行为
     6      * @param fileName
     7      */
     8     public YhdClassPathXmlApplicationContext(String fileName){
     9         this.readXml(fileName);
    10     }
    11     /**
    12      * 根据文件名读取xml的配置文件
    13      * @param fileName
    14      * Administer
    15      * 2013-8-26 下午11:09:16
    16      */
    17     private void readXml(String fileName) {
    18         // TODO Auto-generated method stub
    19         
    20     }
    21 }

    此处readxml啥都没做,现在我们来完成这个代码,根据http://www.cnblogs.com/shunyang/p/3265100.html中提到的方式来解析xml文件,并将解析到的bean存到一个bean定义的类中,为此我们需要准备一个类BeanDefinition 用来存储解析后xml文件。经过分析xml文件,可知比较简单的配置一般有id,class(当然这里为了简单只用了两个)等属性,如下:

    当然我们也需要加上一个全局的List的bean,用来存储所有的beans,代码见后面

     1 package com.juit;
     2 /**
     3  * Bean对象
     4  * @author Administer
     5  *
     6  */
     7 public class BeanDefinition {
     8     private String id;//bean的id
     9     private String className;//bean的类
    10     public String getId() {
    11         return id;
    12     }
    13     public void setId(String id) {
    14         this.id = id;
    15     }
    16     public String getClassName() {
    17         return className;
    18     }
    19     public void setClassName(String className) {
    20         this.className = className;
    21     }
    22     public BeanDefinition(String id, String className) {
    23         this.id = id;
    24         this.className = className;
    25     }
    26 }

    下面是解析xml文件的readXml方法:

     1 private void readXml(String fileName) {
     2         //创建一个读取器
     3         SAXReader saxReader=new SAXReader();
     4         Document document=null;
     5         try {
     6             //获取要读取的配置文件的路径
     7             URL xmlPath=this.getClass().getClassLoader().getResource(fileName);
     8             //读取文件内容
     9             document=saxReader.read(xmlPath);
    10             //获取xml中的根元素
    11             Element rootElement=document.getRootElement();
    12             for (Iterator iterator = rootElement.elementIterator(); iterator.hasNext();) {
    13                 Element element = (Element) iterator.next();
    14                 String id=element.attributeValue("id");//获取bean的id属性值
    15                 String clazz=element.attributeValue("class");//获取bean的class属性值
    16                 BeanDefinition beanDefinition=new BeanDefinition(id,clazz);
    17 beanDefines.add(beanDefinition); 18 } 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 }

     解析完xml后,接下来就是bean的实例化,我们在写一个实例化bean的方法。

    spring中是使用getBean的方式来获取bean的,类似的可以用Map的get取值来模拟,因此定义一个Map,用来存储bean的id和bean的对应,完整的见下面

     
     1 public class YhdClassPathXmlApplicationContext{
     2     private List<BeanDefinition> beanDefines=new ArrayList<BeanDefinition>();//用来存储所有的beans
     3     private Map<String, Object> sigletons =new HashMap<String, Object>();//用来存储实例化后的bean
     4     /**
     5      * 构造方法,用来模拟spring的行为
     6      * @param fileName
     7      */
     8     public YhdClassPathXmlApplicationContext1(String fileName){
     9         //1.读取spring的配置文件
    10         this.readXml(fileName);
    11         //2.实例化bean
    12         this.instanceBeans();
    13     }
    14     /**
    15      * 完成实例化beans
    16      * 
    17      * Administer
    18      * 2013-8-26 下午11:24:37
    19      */
    20     private void instanceBeans() {
    21         // TODO Auto-generated method stub
    22         
    23     }
    
    
    
    
    

     然后我们来完成instanceBeans方法

     1 /**
     2      * 完成实例化beans
     3      * 
     4      * Administer
     5      * 2013-8-18 上午1:07:51
     6      */
     7     private void instanceBeans() {
     8         if (beanDefines != null && beanDefines.size() >0) {
     9             //对每个bean进行实例化
    10             for (BeanDefinition beanDefinition : beanDefines) {
    11                 try {
    12                     //bean的class属性存在的时候才进行实例化,否则不进行实例化
    13                     if (beanDefinition.getClassName() != null && !beanDefinition.getClassName().equals("")) {
    14                         //实例化的关键操作
    15                         sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance());
    16                         System.out.println("id为:"+beanDefinition.getId()+"的bean实例化成功");
    17                     }
    18                 } catch (Exception e) {
    19                     System.out.println("bean实例化失败");
    20                     e.printStackTrace();
    21                 }
    22             }
    23         }
    24     }

     实例化后我们来写一个getBean方法,用来在外部获取实例化后的bean,这个搞个最简单的根据bean的id来获取

     1 /**
     2      * 通过bean名称来获取bean对象
     3      * @param beanName
     4      * @return
     5      * Administer
     6      * 2013-8-18 上午1:17:02
     7      */
     8     public Object getBean(String beanName){
     9         return sigletons.get(beanName);
    10     }

    这样整个bean的实例化我们已经做完了,是不是也不是很困难,当然我们还缺少一步,我们需要测试我们这个自己写的这个spring是不是OK的,

     1 package com.juit;
     2 
     3 import org.junit.BeforeClass;
     4 import org.junit.Test;
     5 
     6 import com.juit.YhdClassPathXmlApplicationContext;
     7 import com.yangyang.service.PersonService;
     8 
     9 public class SpringTest {
    10 
    11     @BeforeClass
    12     public static void setUpBeforeClass() throws Exception {
    13     }
    14 
    15     @Test
    16     public void testInstanceSping() {
    17         YhdClassPathXmlApplicationContext ctx=new YhdClassPathXmlApplicationContext("resources/beans.xml");
    18         PersonService personService=(PersonService)ctx.getBean("personService");
    19 
    20     }
    21 
    22 }

    可以看到控制台打印着"

    id为:personService的bean实例化成功

    终于大功告成了,当然这些只是我这个菜鸟的理解,欢迎各位大神的指导,接下来下篇将会实现spring的依赖注入。

    ----------------------------------------------------------------------------------------
    如果您觉得阅读本文对您有帮助,请微信扫码关注作者,与我进行交流!欢迎各位转载,转载文章之后须在文章页面明显位置给出作者和原文连接,谢谢。
  • 相关阅读:
    String类的常用方法(P小写)
    二维数组:判断是否有目标数
    java实现输入年份判断在哪一天(正则表达式待改进)
    Java实现八进制正整数转化为十进制数
    时钟和定时器
    电路的频率响应---带宽的定义
    stm32两轮平衡车资料
    二阶常系数齐次线性微分方程的解法
    同步积分
    陀螺仪信号解调
  • 原文地址:https://www.cnblogs.com/shunyang/p/3283796.html
Copyright © 2020-2023  润新知