今天看了一下《spring技术内幕》,看了下spring IOC容器的加载过程,但是里面的代码很杂,就自己用源码的测试用例debug了一下看了下过程
测试用例
@Test public void testSingleConfigLocation() throws IOException { ClasspathXmlApplicationContext ctx = new ClasspathXmlApplicationContext(FQ_SIMPLE_CONTEXT); assertTrue(ctx.containsBean("someMessageSource")); LazyBean bean = ctx.getBean(LazyBean.class); Environment environment =ctx.getEnvironment(); String[] profiles =environment.getDefaultProfiles(); for(String s :profiles){ System.out.println(s); } CollectionBean bean2 = (CollectionBean) ctx.getBean("collection"); SingletonBean bean3 = ctx.getBean(SingletonBean.class); SingletonBean bean4 = ctx.getBean(SingletonBean.class); if (bean != null) { System.out.println(bean.getTestFiled()); } if (bean2 != null) { System.out.println(bean2.getList()); } if (bean3 != null) { bean3.process(); } if (bean4 != null) { bean4.process(); } System.out.println(ctx.getBeanDeFinitionCount()); /* * System.out.println(ctx.getBean("lazyBean")); * System.out.println(ctx.getBean("lazyBean")); */ ctx.close(); }
加载过程
static { // Eagerly load the ContextClosedEvent class to avoid weird classloader issues // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.) ContextClosedEvent.class.getName(); }
大概就是说为了避免一些奇怪的问题会首先发布一个ContextClosedEvent事件,然后按照正常的初始化依次初始化父类。
public ClasspathXmlApplicationContext( String[] configLocations,boolean refresh,@Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
- refresh方法会调用AbstractRefreshableApplicationContext中的refreshbeanfactory方法创建一个DefaultListablebeanfactory实例,作为上下文的容器
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); } }
@Override 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); loadBeanDeFinitions(beanDeFinitionReader); } /** * Initialize the bean deFinition reader used for loading the bean * deFinitions of this context. Default implementation is empty. * <p>Can be overridden in subclasses,e.g. for turning off XML validation * or using a different XmlBeanDeFinitionParser implementation. * @param reader the bean deFinition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDeFinitionReader#setDocumentReaderClass */ protected void initBeanDeFinitionReader(XmlBeanDeFinitionReader reader) { reader.setValidating(this.validating); } /** * Load the bean deFinitions with the given XmlBeanDeFinitionReader. * <p>The lifecycle of the bean factory is handled by the {@link #refreshbeanfactory} * method; hence this method is just supposed to load and/or register bean deFinitions. * @param reader the XmlBeanDeFinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn‘t found * @see #refreshbeanfactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ 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); } }
- 这两个方法会用来加载并注册BeanDefiniton,它们又会使用XmlBeanDeFinitionReader来加载xml中的bean的定义,bean定义的解析会使用DefaultBeanDeFinitionDocumentReader,它又会使用BeanDeFinitionParserDelegate类委托解析bean的定义
protected void processBeanDeFinition(Element ele,BeanDeFinitionParserDelegate delegate) {
//委托BeanDeFinitionParserDelegate进行解析 BeanDeFinitionHolder bdHolder = delegate.parseBeanDeFinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDeFinitionIfrequired(ele,bdHolder); try { // Register the final decorated instance. BeanDeFinitionReaderUtils.registerBeanDeFinition(bdHolder,getReaderContext().getRegistry()); } catch (BeanDeFinitionStoreException ex) { getReaderContext().error("Failed to register bean deFinition with name ‘" + bdHolder.getBeanName() + "‘",ele,ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDeFinition(bdHolder)); } }
上面黑体标注的是将解析的BeanDeFinition注册到上下文中的过程,我之前没找到这个方法很奇怪loadBeanDeFinition返回的都是int我就在想,BeanDeFinition哪去了。静态方法会调用BeanDeFinitionRegistry
接口的registerBeanDeFinition方法。而DefaultListablebeanfactory实现了这个接口,
public static void registerBeanDeFinition( BeanDeFinitionHolder deFinitionHolder,BeanDeFinitionRegistry registry) throws BeanDeFinitionStoreException { // Register bean deFinition under primary name. String beanName = deFinitionHolder.getBeanName(); registry.registerBeanDeFinition(beanName,deFinitionHolder.getBeanDeFinition()); // Register aliases for bean name,if any. String[] aliases = deFinitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registeralias(beanName,alias); } } }
到此BeanDeFinition就被注册到了ClasspathXmlApplicationContext中,还有很多细节没贴出来,自己debug一下很有意思的
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。