SpringFramework学习-(3)我的IOC容器

上一篇文章helloworld中展示了SpringIOC容器的效果,那么是怎么实现的呢?
在不看源码的前提下,我们先猜测IOC容器初始化都做了些什么:

ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-helloworld.xml"});
ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"E:\\MavenWorkSpacePrivate\\spring-study-03\\resources\\spring-helloworld.xml"});

Spring提供了两个比较高级的实现,FileSystemXmlApplicationContextClassPathXmlApplicationContext
ClassPathXmlApplicationContext顾名思义就是从classpath下面去寻找配置文件;
FileSystemXmlApplicationContext 顾名思义就是从文件系统中寻找配置文件。
由此可知,初始化IOC容器的第一步应该是资源定位
Spring在得到资源文件之后接下来应该就是加载解析配置文件了。
加载完成的bean会存放在哪里呢,是否需要将这些加载好的bean,注册到某个容器中供使用者调用呢?由getBean(beanName)我们判别加载后的bean应该是存放在了某种Map集合中。

按照上面的猜想和分析,我们按照1)资源定位;2)加载解析;3)注册bean三个步骤来实现以下自己的IOC容器。

创建存储解析后bean的容器
MyBeanDefinition

package com.myspring1.common;

public class MyBeanDefinition {

    private String id;

    private String className;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }


    public MyBeanDefinition(String id, String className) {
        this.id = id;
        this.className = className;
    }

}

创建上下文
MyClassPathXmlApplicationContext

package com.myspring1.common;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 
 * 自定义xml文件加载<br>
 * 分两步:<br>
 * 1)this.getClass().getClassLoader().getResource(xmlFileName)加载xml文件,使用SAX解析xml文件的配置。然后将id,class属性加入到beanDefinition中<br>
 * 2)Class.forName(全类名)实例化解析的bean,并将bean放入到一个map中
 * 
 * @author tang
 * 
 */
public class MyClassPathXmlApplicationContext {

    private List<MyBeanDefinition> myBeanDefines=new ArrayList<MyBeanDefinition>();//用来存储所有的beans

    private Map<String, Object> mySigletons =new HashMap<String, Object>();//用来存储实例化后的bean

    public MyClassPathXmlApplicationContext(String xmlFileName) throws InstantiationException, IllegalAccessException, ClassNotFoundException{

        //1.读取spring配置文件
        this.readXml(xmlFileName);

        //2.实例化beans
        this.instanceBeans();


    }

    /***
     * 读取配置文件,同时将配置文件中的bean都放入到一个集合中
     * @param xmlFileName
     */
    public void readXml(String xmlFileName){
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            //获取要读取的文件的路径
            URL xmlPath = this.getClass().getClassLoader().getResource(xmlFileName);

            document = saxReader.read(xmlPath);

            Element rootElement = document.getRootElement();

            for (Iterator iterator = rootElement.elementIterator(); iterator.hasNext();) {

                Element element = (Element)iterator.next();

                String id = element.attributeValue("id");

                String clazz = element.attributeValue("class");

                MyBeanDefinition myBeanDefinition = new MyBeanDefinition(id, clazz);


                myBeanDefines.add(myBeanDefinition);

            }


        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /***
     * 实例化beans
     * @throws ClassNotFoundException 
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     */
    public void instanceBeans() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
        if(myBeanDefines != null && myBeanDefines.size() > 0){
            for (MyBeanDefinition myBeanDefinition : myBeanDefines) {
                if(myBeanDefinition.getClassName() != null && !"".equals(myBeanDefinition.getClass())){
                    mySigletons.put(myBeanDefinition.getId(), Class.forName(myBeanDefinition.getClassName()).newInstance());
                    System.out.println("id为"+myBeanDefinition.getId()+"的bean实例化成功");
                }
            }
        }
    }

    /**
     * 获取bean
     * @param beanName
     * @return
     */
    public Object getBean(String beanName){
        return mySigletons.get(beanName);
    }   
}

创建需要实例化的bean
UserServiceImpl

package com.myspring1.service;

public interface UserService {

    String findUserById();
}
package com.myspring1.service.impl;

import com.myspring1.service.UserService;

public class UserServiceImpl implements UserService{

    @Override
    public String findUserById() {
        return "myid";
    }   
}

创建配置文件
mySpring1Bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <bean id="userService" class="com.myspring1.service.impl.UserServiceImpl">

    </bean>

</beans>

创建测试类

package com.myspring1.test;

import com.myspring1.common.MyClassPathXmlApplicationContext;
import com.myspring1.service.UserService;

public class SpringTest {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {

        MyClassPathXmlApplicationContext myClassPathXmlApplicationContext = new MyClassPathXmlApplicationContext("mySpring1Bean.xml");

        UserService userService = (UserService)myClassPathXmlApplicationContext.getBean("userService");
        String userId = userService.findUserById();
        System.out.println(userId);
    }
}

测试结果

id为userService的bean实例化成功
myid

实现步骤说明:
1)传入配置文件,定位配置文件的位置,这里使用的获取classpath的方式进行获取的,如果使用文件系统方式需要通过获取文件系统路径进行获取。

URL xmlPath = this.getClass().getClassLoader().getResource(xmlFileName);

2)解析配置文件,加载bean到临时容器中
调用readXml(filename)方法,通过SAX解析器对配置文件进行解析(解析方式是根据xml的约束进行的,所以如果要定义自己的IOC容器,需要先建立自己的dtd约束),然后将将所有的bean都放入到一个叫myBeanDefines的集合中。

this.readXml(xmlFileName);

3)注册bean。如果只是将bean放在myBeanDefines容器中,使用者是无法调用,所以需要将bean注册到map中。id作为key,实例作为value。
这里使用的是反射的机制,通过全类名获取实例。

mySigletons.put(myBeanDefinition.getId(), Class.forName(myBeanDefinition.getClassName()).newInstance());

通过上面的实现,模拟了Spring的实现步骤,但是Sping提供的并没有这么的简单。这是只是展示了简单的实现,依赖注入解耦等等很多的问题也没有考虑进去。

如果想深入的理解SpringIOC,请期待下一篇源码级的解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值