依赖注入(控制反转)是需要依赖注入容器来实现的,ApplicationContext就是最基础的依赖注入容器,它的作用是让Spring能读取XML文件的配置,对bean对象进行创建,修改等。我们可以看下ApplicationContext接口的源码
public abstract interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { ... public abstract AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
里面有用到抽象类AutowireCapableBeanFactory,他的基类就是beanFactory,beanFactory这个接口封装了一系列对配置文件中bean对象的操作方法
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; //根据name获取配置文件中的bean对象 <T> T getBean(Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException; Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
ApplicationContext接口有两个常用实现类,ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,分别是从类加载路径和文件系统中加载配置文件。
那它们究竟是怎么读取这些配置文件的呢?已知配置文件以XML形式保存,那么这两个实现类中必然包含着使用SAX解析XML文件的方法,让我们看看ClassPathXmlApplicationContext的源码吧!
loadBeanDefinitions( )一看就是用来读取配置文件加载bean对象的,里面还有个工厂类,它非常可疑,让我们进去探索下有啥蛛丝马迹!
我们知道,sax解析xml是按从外到内进行解析的,先解析document(文件),再解析entity(实体),最后解析propertity(实体内的元素),所以DefaultDocumentLoader,就是他没跑了,进去看看!
进去后第一眼就能看到这个方法和他的注释
/** * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured * XML parser. */ @Override public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
注释的意思是,用JAXP来解析绑定的XML文件,这是什么意思呢?这里不得不提到InputSource,因为使用sax API时,所有输入都从使用 org.xml.sax.InputSource
类开始,详情见https://blog.csdn.net/linminqin/article/details/6456476
由于水平原因,再底层就脱离Spring的JAR包了,所以就不一一赘述了。不过这一趟探索ApplicationContext还是很有收获的,一言以蔽之,依赖注入是通过SAX读取XML配置文件,再用反射生成bean对象实现的。