基於XML注入的Spring手寫實現筆記

Spring手寫實現筆記

本篇文章並非教你如何基於XML註解實現Spring,僅僅是本人手寫實現Spring XML註解注入的時候一點心得,若是發現有錯誤,還望告知,github連接: https://github.com/laowenruo/... (目前僅僅實現了XML,以後還會實現其餘方式)

基於XML註解實現

原理

  • IOC的做用就是把每一個bean之間的關係交給第三方容器進行管理,bean的初始化等交給容器處理,即控制反轉
  • 全部配置文件只要是配置了全路徑,咱們就能夠理解爲其是反射獲得的(如:spring.xml中配置的bean中的class屬性)
  • SpringIOC的XML版本採用的是dom4j+反射技術實現的
  • 反射的構造對象,確定會走無參構造函數的。(不管構造函數是否私有)

核心實現

定義ApplicationContext

由於咱們使用Spring的Xml注入的時候,咱們是經過ApplicationContext,即應用上下文來加載Xml後獲取對象的,因此咱們第一步先定義一個ApplicaitionContext的接口(爲何要定義成接口,主要是爲了類的設計--單一職責原則)
public interface ApplicationContext{
    /**
     * 根據類名獲取對象,即ByClass
     * @param clazz
     * @return
     * @throws Exception
     */
    Object getBean(Class clazz) throws Exception;

    /**
     * 根據名字獲取對象,即ByName
     * @param beanName
     * @return
     * @throws Exception
     */
    Object getBean(String beanName) throws Exception;
}

定義AbstractApplicationContext

這裏實現得就有點像代理模式了,而且也要引入一個BeanFactory,由於咱們獲取的對象都在BeanFatory裏面構造,說到這裏,咱們可能會想到了部分原理,即ApplicationContext傳入一個XML文件----XML文件轉換爲Resource流-----初始化工廠------讀取Resource流中配置信息到BeanDefinition-----註冊到工廠類----由以前的工廠類建立Bean對象,而且設置各類屬性等
public class AbstractApplicationContext implements ApplicationContext{
    public BeanFactory beanFactory;  //工廠類,實現了工廠模式
    @Override
   public Object getBean(Class clazz) throws Exception {
        return beanFactory.getBean(clazz);
    }

    @Override
    public Object getBean(String beanName) throws Exception {
        return beanFactory.getBean(beanName);
    }
}

定義BeanDefinition

public class BeanDefinition {
    private Object bean;  //實例化後的對象
    private Class beanClass;
    private String beanClassName;
    private Boolean singleton; //是否爲單例模式
    private PropertyValues propertyValues;   //這個也就是屬性的鍵值對了

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public PropertyValues getPropertyValues() {
        if(propertyValues == null) {
            propertyValues = new PropertyValues();
        }
        return propertyValues;
    }

    public void setPropertyValues(PropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }

    public Boolean isSingleton() {
        return singleton;
    }

    public void setSingleton(Boolean singleton) {
        this.singleton = singleton;
    }
}

定義ClassPathXmlApplicationContext

public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    private final Object startupShutdownMonitor = new Object();
    private String location;

    public ClassPathXmlApplicationContext(String location) throws Exception {
        super();
        this.location = location;
        refresh();
    }

    public void refresh() throws Exception {
        synchronized (startupShutdownMonitor) {
            AbstractBeanFactory beanFactory = obtainBeanFactory();
            prepareBeanFactory(beanFactory);
            this.beanFactory = beanFactory;
        }
    }

    private void prepareBeanFactory(AbstractBeanFactory beanFactory) throws Exception {
        beanFactory.populateBeans();
    }

    private AbstractBeanFactory obtainBeanFactory() throws Exception {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        beanDefinitionReader.loadBeanDefinitions(location);
        AbstractBeanFactory beanFactory = new AutowiredCapableBeanFactory();
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }
        return beanFactory;
    }

}

定義XmlBeanDefinitionReader

/**
 * XML配置文件形式的Bean定義讀取類
 *
 * @author ziyang
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
        super(resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(String location) throws Exception {
        InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
        doLoadBeanDefinitions(inputStream);
    }

    protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        Document document = documentBuilder.parse(inputStream);
        // 解析xml document並註冊bean
        registerBeanDefinitions(document);
        inputStream.close();
    }

    public void registerBeanDefinitions(Document document) {
        Element root = document.getDocumentElement();
        // 從文件根遞歸解析
        parseBeanDefinitions(root);
    }

    protected void parseBeanDefinitions(Element root) {
        NodeList nodeList = root.getChildNodes();
        for(int i = 0; i < nodeList.getLength(); i ++) {
            Node node = nodeList.item(i);
            if(node instanceof Element) {
                processBeanDefinition((Element) node);
            }
        }
    }

    protected void processBeanDefinition(Element ele) {
        String name = ele.getAttribute("id");
        String className = ele.getAttribute("class");
        boolean singleton = true;
        if(ele.hasAttribute("scope") && "prototype".equals(ele.getAttribute("scope"))) {
            singleton = false;
        }
        BeanDefinition beanDefinition = new BeanDefinition();
        processProperty(ele, beanDefinition);
        beanDefinition.setBeanClassName(className);
        beanDefinition.setSingleton(singleton);
        getRegistry().put(name, beanDefinition);
    }

    private void processProperty(Element ele, BeanDefinition beanDefinition) {
        NodeList propertyNode = ele.getElementsByTagName("property");
        for(int i = 0; i < propertyNode.getLength(); i ++) {
            Node node = propertyNode.item(i);
            if(node instanceof Element) {
                Element propertyEle = (Element) node;
                String name = propertyEle.getAttribute("name");
                String value = propertyEle.getAttribute("value");
                if(value != null && value.length() > 0) {
                    // 優先進行值注入
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                } else {
                    String ref = propertyEle.getAttribute("ref");
                    if(ref == null || ref.length() == 0) {
                        throw new IllegalArgumentException("Configuration problem: <property> element for property '" + name + "' must specify a ref or value");
                    }
                    BeanReference beanReference = new BeanReference(ref);
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
                }
            }
        }
    }

}

總結

  • ClassPathXmlApplication傳入xml文件的路徑,而且在構造函數中調用refresh方法
  • 在這個方法中由AbstractBeanFactory定義了一個工廠類,而且調用了obtainBeanFatcory方法,在方法中調用了XmlBeanDefinitionReader類,這個類將XML轉換成Resource流,而且讀取了其中的key和value值,value值就是BeanDefinition
  • 由AutowiredCapableBeanFactory(自動裝配工廠類)定義一個工廠,將上述的Key和Value註冊到工廠中而且返回到上面定義的工廠類,即將BeanDefinition註冊到工廠類中
  • 最後調用prepareBeanFactory方法,層層嵌套後是調用doCreateBean方法,將對象中的屬性注入對象中,返回Bean到工廠中,此時BeanDefinition中的bean中就是一個實例化後、具備屬性設置的對象了
  • 以後,你就能夠經過ByName或者ByClass來獲取你的對象了
相關文章
相關標籤/搜索