Spring IOC 源码解析

来源:互联网 发布:陈一发 知乎 编辑:程序博客网 时间:2024/04/28 17:30

参考资料:http://www.iteye.com/topic/86339


Person类:

                  

      public class Person {               public void test(){                     System.out.println("~~~~~~~~~~~~~~");               }      }


Test类:

           

       public static void main(String[] args) {              <span style="color:#FF0000;"> FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext(               "C:/Users/Administrator/Desktop/beanTest.xml");</span>               Person p = (Person) fileSystemXmlApplicationContext.getBean("person");               p.test();       }


debug:

             1:进入FileSystemXmlApplicationContext里的构造函数:

             

        public FileSystemXmlApplicationContext(String configLocation) throws BeansException {<span style="color:#FF0000;">this(new String[] {configLocation}, true, null);</span>}

             2.继续调到另一个构造函数
        public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);<span style="color:#FF0000;">setConfigLocations(configLocations);if (refresh) { refresh(); }</span> }

                2.1setConfigLocations(configLocations)解释:

                      AbstractRefreshableConfigApplicationContext是FileSystemXmlApplicationContext的父类

                      直接调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)

                      获取配置文件的路径(C:/Users/Administrator/Desktop/beanTest.xml)

       public void setConfigLocations(String[] locations) { if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) { this.configLocations[i] = resolvePath(locations[i]).trim();} } else { this.configLocations = null;} }


                2.2 refresh解释:调用AbstractApplicationContext的refresh()方法

               

        if (refresh) {     refresh();        }


        public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.<span style="color:#FF0000;">prepareRefresh()</span>;// Tell the subclass to refresh the internal bean factory.<span style="color:#FF0000;">ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();</span>// Prepare the bean factory for use in this context.<span style="color:#330033;">prepareBeanFactory(beanFactory);</span>try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}}}

               2.3prepareRefresh()准备工作

                    取当前时间和置一个状态

        protected void prepareRefresh() {<span style="color:#FF0000;">this.startupDate = System.currentTimeMillis();</span><span style="color:#FF0000;">synchronized (this.activeMonitor) {this.active = true;}</span>if (logger.isInfoEnabled()) {logger.info("Refreshing " + this);}// Initialize any placeholder property sources in the context environmentinitPropertySources();// Validate that all properties marked as required are resolvable// see ConfigurablePropertyResolver#setRequiredPropertiesgetEnvironment().validateRequiredProperties();}

                2.4ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                ioc容器开始初始化

               

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {<span style="color:#FF0000;">refreshBeanFactory();</span>ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;}

               2.5 refreshBeanFactory()进行刷新beanFactory

                      在AbstractApplicationContext的子类AbstractRefreshableApplicationContext

                      如果当前有beanFactory的话,那么销毁所有的bean,关闭beanFactory

                      如果当前没有beanFactory的话,创建beanFactory,加载bean的实例

       protected final void refreshBeanFactory() throws BeansException {if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);<span style="color:#FF0000;">loadBeanDefinitions(beanFactory);</span>synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

               2.6 loadBeanDefinitions(beanFactory)

                      进入到AbstractXmlApplicationContext类里的loadBeanDefinitions(beanFactory)

                     创建XmlBeanDefinitionReader

       protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);<span style="color:#FF0000;">loadBeanDefinitions(beanDefinitionReader);</span>}

                2.7 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) {<span style="color:#FF0000;">reader.loadBeanDefinitions(configLocations);</span>}}

               2.8 reader.loadBeanDefinitions(configLocations);

                     进入AbstractBeanDefinitionReader类里

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;for (String location : locations) {<span style="color:#FF0000;">counter += loadBeanDefinitions(location);</span>}return counter;}

                2.9  loadBeanDefinitions(location)

                       

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {<span style="color:#FF0000;">return loadBeanDefinitions(location, null);</span>}

               2.10  loadBeanDefinitions(location, null)

              

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {<span style="color:#FF0000;">Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);</span><span style="color:#FF0000;">int loadCount = loadBeanDefinitions(resources);</span>if (actualResources != null) {for (Resource resource : resources) {actualResources.add(resource);}}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// Can only load single resources by absolute URL.Resource resource = resourceLoader.getResource(location);int loadCount = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;}}

                2.11 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

                        跳进AbstractApplicationContext类里

                       

public Resource[] getResources(String locationPattern) throws IOException {<span style="color:#FF0000;">return this.resourcePatternResolver.getResources(locationPattern);</span>}

               2.12 跳进PathMatchingResourcePatternResolver类里

               判断配置文件是那种类型的相应跳到哪个实现类里

public Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern);}else {// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));}}else {// Only look for a pattern after a prefix here// (to not get fooled by a pattern symbol in a strange prefix).int prefixEnd = locationPattern.indexOf(":") + 1;if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern);}else {// a single resource with the given name<span style="color:#FF0000;">return new Resource[] {getResourceLoader().getResource(locationPattern)};</span>}}}

                2.13 跳进DefaultResourceLoader类(我的配置文件的类型对象的是该resourceLoader)

               

public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");if (location.startsWith(CLASSPATH_URL_PREFIX)) {return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());}else {try {// Try to parse the location as a URL...URL url = new URL(location);return new UrlResource(url);}catch (MalformedURLException ex) {// No URL -> resolve as resource path.<span style="color:#FF0000;">return getResourceByPath(location);</span>}}}

                2.14 返回FileSystemXmlApplicationContext类

                 创建FileSystemResource

protected Resource getResourceByPath(String path) {if (path != null && path.startsWith("/")) {path = path.substring(1);}return new FileSystemResource(path);}

               2.15 返回到2.10 里的 方法里

               转化成resource对象

               继续debug,进入int loadCount = loadBeanDefinitions(resources);这句话

              

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");int counter = 0;for (Resource resource : resources) {<span style="color:#FF0000;">counter += loadBeanDefinitions(resource);</span>}return counter;}

                2.16 进入到XmlBeanDefinitionReader类 他是属于abstractBeanDefinitionReader的实现之一

               

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {<span style="color:#FF0000;">return loadBeanDefinitions(new EncodedResource(resource));</span>}

                把配置文件转化成流,进行加载bean,到这个方法才开始真正的加载bean
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());}<span style="color:#FF0000;">return doLoadBeanDefinitions(inputSource, encodedResource.getResource());</span>}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();}}}

                2.17  开始进行注册bean

                          把刚刚的流生成document对象进行注册

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {Document doc = doLoadDocument(inputSource, resource);<span style="color:#FF0000;">return registerBeanDefinitions(doc, resource);</span>}catch (BeanDefinitionStoreException ex) {throw ex;}catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);}catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"XML document from " + resource + " is invalid", ex);}catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Parser configuration exception parsing XML from " + resource, ex);}catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"IOException parsing XML document from " + resource, ex);}catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Unexpected exception parsing XML document from " + resource, ex);}}

               
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();documentReader.setEnvironment(this.getEnvironment());int countBefore = getRegistry().getBeanDefinitionCount();<span style="color:#FF0000;">documentReader.registerBeanDefinitions(doc, createReaderContext(resource));</span>return getRegistry().getBeanDefinitionCount() - countBefore;}

                2.18 进入到DefaultBeanDefinitionDocumentReader

                         开始进入解析xml

                        

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();<span style="color:#FF0000;">doRegisterBeanDefinitions(root);</span>}

               
protected void doRegisterBeanDefinitions(Element root) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {Assert.state(this.environment != null, "Environment must be set for evaluating profiles");String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);if (!this.environment.acceptsProfiles(specifiedProfiles)) {return;}}// Any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(this.readerContext, root, parent);preProcessXml(root);<span style="color:#FF0000;">parseBeanDefinitions(root, this.delegate)</span>;postProcessXml(root);this.delegate = parent;}

               
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {<span style="color:#FF0000;">parseDefaultElement(ele, delegate);</span>}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}

               
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}

                到此为止,现在就把bean已经加载注册完成了~~~

              

                    

               

               

             




                

0 0
原创粉丝点击