乐趣区

关于java:基于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 来获取你的对象了
退出移动版