Spring容器启动 1 2 3 public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("classpath:applicationfile.xml" ); }
ApplicationContext context = new ClassPathXmlApplicationContext(...)
就是在 ClassPath 中寻找 xml 配置文件,根据 xml 文件内容来构建 ApplicationContext。
简单介绍一下FileSystemXmlApplicationContext 和 AnnotationConfigApplicationContext 这两个类
1、FileSystemXmlApplicationContext 的构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。
2、AnnotationConfigApplicationContext 是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置,是比较简单的方式。
利用ClassPathXmlApplicationContext类创建一个实例:
首先,定义一个接口:
1 2 3 public interface MessageService { String getMessage () ; }
定义接口实现类:
1 2 3 4 5 6 public class MessageServiceImpl implements MessageService { public String getMessage () { return "hello world" ; } }
接下来,我们在 resources 目录新建一个配置文件,文件名随意,通常叫 application.xml 或 application-xxx.xml 就可以了:
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire ="byName" > <bean id ="messageService" class ="com.javadoop.example.MessageServiceImpl" /> </beans >
这样,我们就可以跑起来了:
1 2 3 4 5 6 7 8 9 10 11 12 13 public class App { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("classpath:application.xml" ); System.out.println("context 启动成功" ); MessageService messageService = context.getBean(MessageService.class); System.out.println(messageService.getMessage()); } }
BeanFactory 顾名思义,就是一个生产Bean的工厂,负责生产和管理各个Bean实例,刚刚所说的ApplicationContext 实际上就是一个BeanFactory,BeanFactory接口继承结构如下:
ListableBeanFactory:根据句Listable可知通过这个接口我们可以获取多个Bean,但是顶层BeanFactory只能每次获取单个Bean实例
HierarchicalBeanFactory:通过Hierarchical这个单词可知,我们可以通过这个接口创建多个BeanFactory(不是多个Bean实例 ),然后将多个BeanFactory设置为父子关系。
AutowireCapableBeanFactory 用于自动装配Bean的,虽然ApplicationContext 没有继承它,但是可以使用组合,ApplicationContext 的最后一个方法getAutowireCapableBeanFactory()就是组合使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 public interface ApplicationContext extends EnvironmentCapable , ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { String getId () ; String getApplicationName () ; String getDisplayName () ; long getStartupDate () ; ApplicationContext getParent () ; AutowireCapableBeanFactory getAutowireCapableBeanFactory () throws IllegalStateException; }
ConfigurableListableBeanFactory 这个接口比较特殊,继承了第二层的所有三个接口,但是ApplicationContext 没有
启动过程分析 ClassPathXmlApplicationContext 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { private Resource[] configResources; public ClassPathXmlApplicationContext (ApplicationContext parent) { super (parent); } ... public ClassPathXmlApplicationContext (String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ... }
refresh()方法 介绍一下refresh方法,因为他是ClassPathXmlApplicationContext类构造方法的核心方法,它主要的作用就是用于重建,refresh方法会将原来的ApplicationContext销毁然后重新执行一次初始化操作。源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
创建 Bean 容器前的准备工作 prepareRefresh()就是用来创建Bean容器之前的准备工作,在讲refresh方法中讲到过,主要是记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected void prepareRefresh () { this .startupDate = System.currentTimeMillis(); this .closed.set(false ); this .active.set(true ); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this ); } initPropertySources(); getEnvironment().validateRequiredProperties(); this .earlyApplicationEvents = new LinkedHashSet <ApplicationEvent>(); }
创建Bean容器,加载并注册Bean obtainFreshBeanFactory() 方法就是用于初始化BeanFactory、加载Bean、注册Bean等这个方法是refresh中最重要的一个部分,但是这个方法执行结束之后Bean实例并没有生成,也就是说Bean没有完成初始化。
1 2 3 4 5 6 7 8 9 10 11 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException ("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
为什么选择实例化 DefaultListableBeanFactory ?
前面的BeanFactory中有一个接口叫做ConfigurableListableBeanFactory,它实现了BeanFactory下面一层的所有三个接口,而这个接口只有一个实现类DefaultListableBeanFactory,而实现类DefaultListableBeanFactory实际上间接实现了BeanFactory下的三个接口,所以结论就是,DefaultListableBeanFactory是最牛的BeanFactory。例图如下
customizeBeanFactory(beanFactory)方法就是配置是否允许BeanDefinition覆盖、是否允许循环引用。
1 2 3 4 5 6 7 8 9 10 protected void customizeBeanFactory (DefaultListableBeanFactory beanFactory) { if (this .allowBeanDefinitionOverriding != null ) { beanFactory.setAllowBeanDefinitionOverriding(this .allowBeanDefinitionOverriding); } if (this .allowCircularReferences != null ) { beanFactory.setAllowCircularReferences(this .allowCircularReferences); } }
loadBeanDefinitions(beanFactory)就是根据配置,加载各个Bean,然后放到BeanFactory中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader (beanFactory); beanDefinitionReader.setEnvironment(this .getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver (this )); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions (XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } } public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int counter = 0 ; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; } public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet <EncodedResource>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException ( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException ( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } catch (... } public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; logger.debug("Loading bean definitions" ); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }