如何理解容器SpringIOC
本篇内容介绍了“如何理解容器Spring IOC”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
为崇左等地区用户提供了全套网页设计制作服务,及崇左网站建设行业解决方案。主营业务为成都网站设计、网站建设、崇左网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
构造bean工厂类
/** * Create a new XmlBeanFactory with the given resource, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @param parentBeanFactory parent bean factory * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); }
我们使用的就是第一个构造,但是第一个构造调用了第二个,第二个构造只有两步。我们继续往下看
再来看XmlBeanFactory初始化的源码
super(parentBeanFactory):用来初始化父类
this.reader.loadBeanDefinitions(resource):spring初始化资源加载的真正实现
我们先来看看“super(parentBeanFactory):用来初始化父类”这一步做了什么吧
/** * 先是调用DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory)带参构造方法 */ public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) { super(parentBeanFactory); } /** * 调用父类AbstractAutowireCapableBeanFactory */ public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) { this(); setParentBeanFactory(parentBeanFactory); } /** * 调用AbstractAutowireCapableBeanFactory()无参构造方法 */ public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); } /** * 在初始化XmlBeanFactory容器 */ public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) { if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) { throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory); } this.parentBeanFactory = parentBeanFactory; }
到这里是不是比较明了的知道了这一步具体做了什么?其实看完super(parentBeanFactory)的源码发现就做了两件事:获取添加需要忽略指定接口实现类的自动装配和初始化。那我们的第二步具体做了什么呢?
this.reader.loadBeanDefinitions(resource)分析
之前我们说了我们应该是根据配置文件找到对应的类,那源码是这样吗?看看这句代码的实现就知道了。
/** * 先是调用loadBeanDefinitions(Resource resource) */ public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } /** * 这个方法正是我们之前推测的实现 * 从xml配置文件中加载bean */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } SetcurrentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(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(); } } }
当我们贴完代码之后,是不是可以明显的看到我们之前推测的实际证据?
ClassPathResource和InputStream
我们从上面的源码看到,我们定义的类在xml中,源码里面有InputStream。但是传入的只有一个ClassPathResource。那他是怎么封装进入ClassPathResource的呢?
其实这里的关联比较简单。我们不妨来看看这些类的类结构图
到这里是不是就已经很明了了我们的InputStream是怎么将内容传递进入ClassPathResource
真正获取bean
获取bean才是我们这一段操作的最关键的地方,那bean又是怎么获取出来的呢?这里贴一下主代码吧
protectedT doGetBean(final String name, @Nullable final Class requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
仅从代码量上就能看出来bean的加载经历了一个相当复杂的过程,其中涉及各种各样的考虑。
我们将上面的内容大致总结一下:
转换对应beanName。
尝试从缓存中加载单例。
bean的实例化。
原型模式的依赖检查。
检测parentBeanFactory。
将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。
寻找依赖。
针对不同的scope进行bean的创建。
类型转换。(强转)
“如何理解容器Spring IOC”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!
文章标题:如何理解容器SpringIOC
分享地址:http://scyanting.com/article/iigihe.html