spring技术内幕读书笔记--IOC
来源:互联网 发布:淘宝怎么买食品 编辑:程序博客网 时间:2024/05/16 08:54
今天对《spring技术内幕》一书中有关IOC容器实现的章节做一个简单总结。
IOC容器的设计与实现
- IoC容器设计中,两个主要的接口
1)BeanFactory:可以理解为IoC容器的抽象,提供了ioc容器的最基本API。
2)ApplicationContext:IoC容器的高级形态,在基础IoC容器上加了许多特性。
从继承图来理解:
DefaultListableBeanFactory是IoC容器的最基础实现,是一个最基础最简单的IoC容器对象,其高级容器ApplicationContext也是通过持有DefaultListableBeanFactory引用,在基础IoC容器之上进行特性增强。
- 容器设计原理
XmlBeanFactory这个IoC容器便是在DefaultListableBeanFactory基础容器之上,添加了如xml读取的附加功能。
编程式使用IoC容器示例
ClassPathResource res = new ClassPathResource("bean.xml");DefaultListableBeanFactory factory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);reader.loadBeanDefinitions(res);
大致过程如下几步:
1)读取bean.xml配置文件资源
2)创建基础BeanFactory容器(DefaultListableBeanFactory)
3)创建资源读取器(XmlBeanDefinitionReader),并将其与BeanFactory容器对象进行关联
4)将bean.xml配置文件中的信息解析成BeanDefinition元数据信息对象,并注册到BeanFactory(IoC容器)中
- ApplicationContext容器特点
ApplicationContext通过对不同特性接口的实现为基础IoC容器添加了许多特性
1)MessageSource接口:支持不同的信息源。
2)ResourceLoader和Resource接口:支持从不同的途径获取资源信息。
3)ApplicationEventPublisher接口:支持应用事件。
4)ApplicationContext接口:在基本IoC容器基础上增加附加服务。
IoC容器的初始化过程
IoC容器启动的三个基本过程
1)Resource资源信息定位
2)BeanDefinition的载入(将资源中的信息初始化为BeanDefinition对象)
3)向IoC容器注册生成的BeanDefinition对象
下面我们通过FileSystemXmlApplicationContext为例,进行IoC容器初始化过程的解析
FileSystemXmlApplicationContext是一个支持xml定义BeanDefinition的ApplicationContext,我们看一下
FileSystemXmlApplicationContext的具体实现
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext() { } public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent); } public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null); } public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent); } public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, null); } // 调用refresh函数载入和注册BeanDefinition对象,完成IoC容器的初始化过程 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } // 构造一个FileSystemResource来获取资源文件,此方法是在BeanDefinitionReader的loadBeanDefintion中被调用 // loadBeanDefintion方法是一个抽象,具体的资源定位的实现由具体的子类来完成 @Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }}
这里的refresh方法是IoC容器初始化的唯一入口
初始化调用过程大致如下:
IoC容器执行refresh的过程
其中最主要的BeanDefintion对象的载入和注册过程是在
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()中refreshBeanFactory方法中完成
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 创建ioc容器 // new DefaultListableBeanFactory(getInternalParentBeanFactory()) DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); // 启动BeanDefinition的载入和注册过程 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
这里的loadBeanDefinitions方法中会创建XmlBeanDefinitionReader对象,并启动BeanDefinitionReader的getResourceLoader方法
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // 以Resource的方式获取配置文件的资源位置 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } // 以String的方式获取配置文件的资源位置 String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
BeanDefinitionReader抽象中会完成配置文件的资源的加载
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 { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); 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 { // 调用具体实现容器的getResourceByPath方法获取Resource handle对象并根据具体实现加载配置资源 Resource resource = resourceLoader.getResource(location); // 加载和注册BeanDefinition元信息对象,具体由XmlBeanDefinitionReader实现 int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
XmlBeanDefinitionReader中loadBeanDefinitions的具体实现
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 { // 准备IO流来获取配置资源中的数据 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(); } } } /** * Actually load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors * @see #doLoadDocument * @see #registerBeanDefinitions */ // 真正开始从指定的资源文件中获取信息,加载并注册BeanDefinition到IoC中 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 通过DefaultDocumentLoader对象获取xml配置文件的Document对象 Document doc = doLoadDocument(inputSource, resource); // 将获取的Document对象解析成BeanDefinition对象,并注册到IoC容器中 return registerBeanDefinitions(doc, resource); } 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); } }
将获取的Document对象解析成BeanDefinition对象的具体实现由BeanDefinitionParserDelegate解析器具体实现完成
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 将Document对象解析成BeanDefinition对象的具体方法 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //将解析好的BeanDefinition注册到DefaultListableBeanFactory容器对象中 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
具体的Document解析成BeanDefinition的过程是通过不断的递归调用完成,具体实现这里不做分析
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); // 获取定义的<bean>中设置的bean的name,设置到BeanDefinition对象中去 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } // 创建BeanDefinition对象 AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 对bean元素的属性进行解析 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析<bean>的构造函数设置 parseConstructorArgElements(ele, bd); // 解析<bean>的property设置 parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
而注册则是将BeanDefinition对象放入到DefaultListableBeanFactory容器中维护的一个map中
this.beanDefinitionMap.put(beanName, beanDefinition);
至此,IoC容器的初始化过程就完成了。
总结:IoC容器的初始化过程就是将xml配置资源的信息抽象到BeanDefinition信息对象中,再将BeanDefinition设置到基本容器的map中,BeanDefinition中的信息是容器建立依赖反转的基础,IoC容器的作用就是对这些信息进行处理和维护。
IoC容器的依赖注入
依赖注入是用户第一次向IoC容器索要Bean时触发的,入口为DefaultListableBeanFactory基类AbstractBeanFactory中的getBean方法
具体依赖注入过程
图中的AbstractAutowireCapableBeanFactory类是具体实现依赖注入的主要实现类,bean对象的正式实例化,bean依赖对象的注入,bean对象的初始化回调都在此类中完成。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 通过CGLIB类库,反射bean的构造器创建bean实例 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } Object exposedObject = bean; try { // 对bean对象进行依赖注入 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { // 对bean对象进行初始化方法的回调 exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
populateBean进行目标对象的依赖注入时的大致执行流程
具体调用为递归getBean方法完成,不做具体分析。
在对bean对象完成依赖注入后,会调用AbstractAutowireCapableBeanFactory.initializeBean方法对bean对象进行初始化回调
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // BeanPostProcessor接口前置监听 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // BeanPostProcessor接口后置监听 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } } protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
这里我们看到初始化接口的回调顺序
BeanNameAware —-> BeanClassLoaderAware —-> BeanFactoryAware —-> BeanPostProcessor.postProcessBeforeInitialization —-> InitializingBean —-> init-method方法 —->
BeanPostProcessor.postProcessAfterInitialization
到此,IoC容器的整个初始化过程基本结束。
容器销毁
容器的销毁通过AbstractApplicationContext.doClose方法完成
总结:
简单总结一下IoC容器的bean生命周期
1)Bean实例的创建
2)为Bean实例设置属性
3)调用Bean的初始化接口方法
4)应用可以通过IoC容器获取bean
5)当容器关闭时,调用Bean的销毁方法。
- spring技术内幕读书笔记--IOC
- spring 技术内幕--IOC
- Spring技术核心内幕 读书笔记--IOC容器的实现小结
- Spring 技术内幕-读书笔记
- spring技术内幕2读书笔记
- spring技术内幕读书笔记--AOP
- spring技术内幕读书笔记--事务处理
- 读书笔记-《Spring技术内幕》-计文柯(一):IoC容器的实现
- spring技术内幕1-IOC容器体系结构
- Spring技术内幕(一):IOC容器
- spring技术内幕 读书笔记(一)
- spring技术内幕 读书笔记(二)
- spring技术内幕读书笔记--springmvc组件
- spring技术内幕2-IOC定位Bean定义资源
- spring技术内幕3-IOC容器载入Bean定义资源
- spring技术内幕5-IoC容器的依赖注入
- spring技术内幕6-IoC容器的高级特性
- Spring技术内幕笔记 -- IoC容器的实现
- 判断一个单链表中是否有环
- 二叉树的层次遍历
- java只使用try和finally不使用catch的原因和场景
- Android log.e(),log.d(),log.i()等的区别
- Oracle之数据库恢复到某个时间点-yellowcong
- spring技术内幕读书笔记--IOC
- WebView java.lang.NoSuchMethodException:callDrawGLFunction
- RecyclerView 获取 item 的位置
- 数据库查询优化之用exists替换in,not exists替换not in
- BugKu MISC 部分题目Write_up(一)
- 1121: 电梯
- BitmapUtil 工具类
- spring autowired
- servlet与cgi的区别与关系(1)--两者区别