Spring学习-IOC容器

张开发
2026/4/8 22:12:58 15 分钟阅读

分享文章

Spring学习-IOC容器
Spring IOC容器和Beans的介绍该部分讲解Spring对控制反转的实现。依赖注入是控制反转的一种特殊形式。其中对象仅通过构造函数参数工厂方法的参数或者通过构造函数创建或者从工厂方法返回的对象实例设置的属性来定义它们的依赖。IOC容器在创建Bean后会将其注入到那些依赖中。这个过程从根本上来说是bean本身控制其依赖项的实例化或者定位通过直接使用类的构造器或者服务定位器模式等机制的逆过程。org.springframework.beans和org.springframework.context包是Spring框架IOC容器的基础。BeanFactory接口提供了一种高级的配置机制能够管理任何类型的对象。ApplicationContext是BeanFactory的子接口。总而言之BeanFactory提供了一个配置框架和基本的功能能力并且ApplicationContext添加了更多特定企业的功能。ApplicationContext是BeanFactory的完全超集。容器概述上图展示了Spring如何工作的高级视图。你的应用的类们和配置元数据相结合这样在ApplicationContext创建并初始化后就拥有了一个完全配置且可执行的系统或应用程序。使用示例配置元数据dao.xml?xml version1.0 encodingUTF-8?beansxmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdbeanidaccountDaoclasscom.example.demo.dao.AccountDaopropertynamenamevalue账户/!-- collaborators and configuration for this bean go here --/beanbeaniditemDaoclasscom.example.demo.dao.ItemDaopropertynamenamevaluecat/!-- collaborators and configuration for this bean go here --/bean!-- more bean definitions go here --/beansservice.xml?xml version1.0 encodingUTF-8?beansxmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdimportresourcedao.xml/beanidpetStoreclasscom.example.demo.service.PetStoreService!-- collaborators and configuration for this bean go here --propertynameaccountDaorefaccountDao/propertynameitemDaorefitemDao//bean!-- more bean definitions go here --/beans业务类daopackagecom.example.demo.dao;publicclassAccountDao{privateStringname;AccountDao(){}AccountDao(Stringname){this.namename;}publicvoidsetName(Stringname){this.namename;}publicStringgetName(){returnname;}}packagecom.example.demo.dao;publicclassItemDao{privateStringname;ItemDao(){}ItemDao(Stringname){this.namename;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}}servicepackagecom.example.demo.dao;publicclassItemDao{privateStringname;ItemDao(){}ItemDao(Stringname){this.namename;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}}main方法packagecom.example.demo;importcom.example.demo.service.PetStoreService;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(DemoApplication.class,args);// 创建和配置对象ApplicationContextcontextnewClassPathXmlApplicationContext(service.xml,dao.xml);// 检索配置的实例PetStoreServiceservicecontext.getBean(petStore,PetStoreService.class);// 使用service.printInfo();}}ApplicationContext源码学习执行如下代码创建和配置对象java ApplicationContext context new ClassPathXmlApplicationContext(service.xml, dao.xml);创建配置对象后主要干两件事一件事将传入的配置文件信息设置给configLocations变量。一件事是刷新上下文刷新上下文其实就是更新环境中的beanFactory和bean信息。publicClassPathXmlApplicationContext(String[]configLocations,booleanrefresh,NullableApplicationContextparent)throwsBeansException{super(parent);setConfigLocations(configLocations);if(refresh){refresh();}}refresh代码如下该代码为AbstractApplicationContext的实现。该部分代码主要干两件事一个是beanFactory的初始化和设置操作一个是通过beanFactory创建对象。最后清空spring的缓存。Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){StartupStepcontextRefreshthis.applicationStartup.start(spring.context.refresh);// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try{// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStepbeanPostProcessthis.applicationStartup.start(spring.context.beans.post-process);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 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(BeansExceptionex){if(logger.isWarnEnabled()){logger.warn(Exception encountered during context initialization - cancelling refresh attempt: ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset active flag.cancelRefresh(ex);// Propagate exception to caller.throwex;}finally{// Reset common introspection caches in Springs core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}BeanFactory组件源码applicationContext中执行如下代码进行bean的初始化每个bean在整个容器中只有一个。// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);finishBeanFactoryInitialization会调用beanFactory组件的preInstantiateSingletons方法。该beanFactory为DefaultListableBeanFactory类的实例。// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();该方法会调用AbstractBeanFactory的doGetBean方法。protectedTTdoGetBean(Stringname,NullableClassTrequiredType,NullableObject[]args,booleantypeCheckOnly)throwsBeansException{StringbeanNamethis.transformedBeanName(name);ObjectsharedInstancethis.getSingleton(beanName);ObjectbeanInstance;if(sharedInstance!nullargsnull){if(this.logger.isTraceEnabled()){if(this.isSingletonCurrentlyInCreation(beanName)){this.logger.trace(Returning eagerly cached instance of singleton bean beanName that is not fully initialized yet - a consequence of a circular reference);}else{this.logger.trace(Returning cached instance of singleton bean beanName);}}beanInstancethis.getObjectForBeanInstance(sharedInstance,name,beanName,(RootBeanDefinition)null);}else{if(this.isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName);}BeanFactoryparentBeanFactorythis.getParentBeanFactory();if(parentBeanFactory!null!this.containsBeanDefinition(beanName)){StringnameToLookupthis.originalBeanName(name);if(parentBeanFactoryinstanceofAbstractBeanFactory){return(T)((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup,requiredType,args,typeCheckOnly);}if(args!null){return(T)parentBeanFactory.getBean(nameToLookup,args);}if(requiredType!null){return(T)parentBeanFactory.getBean(nameToLookup,requiredType);}return(T)parentBeanFactory.getBean(nameToLookup);}if(!typeCheckOnly){this.markBeanAsCreated(beanName);}StartupStepbeanCreationthis.applicationStartup.start(spring.beans.instantiate).tag(beanName,name);try{if(requiredType!null){beanCreation.tag(beanType,requiredType::toString);}RootBeanDefinitionmbdthis.getMergedLocalBeanDefinition(beanName);this.checkMergedBeanDefinition(mbd,beanName,args);String[]dependsOnmbd.getDependsOn();if(dependsOn!null){for(Stringdep:dependsOn){if(this.isDependent(beanName,dep)){thrownewBeanCreationException(mbd.getResourceDescription(),beanName,Circular depends-on relationship between beanName and dep);}this.registerDependentBean(dep,beanName);try{this.getBean(dep);}catch(NoSuchBeanDefinitionExceptionex){thrownewBeanCreationException(mbd.getResourceDescription(),beanName,beanName depends on missing bean dep,ex);}}}if(mbd.isSingleton()){sharedInstancethis.getSingleton(beanName,()-{try{returnthis.createBean(beanName,mbd,args);}catch(BeansExceptionex){this.destroySingleton(beanName);throwex;}});beanInstancethis.getObjectForBeanInstance(sharedInstance,name,beanName,mbd);}elseif(mbd.isPrototype()){ObjectprototypeInstancenull;try{this.beforePrototypeCreation(beanName);prototypeInstancethis.createBean(beanName,mbd,args);}finally{this.afterPrototypeCreation(beanName);}beanInstancethis.getObjectForBeanInstance(prototypeInstance,name,beanName,mbd);}else{StringscopeNamembd.getScope();if(!StringUtils.hasLength(scopeName)){thrownewIllegalStateException(No scope name defined for bean beanName);}Scopescope(Scope)this.scopes.get(scopeName);if(scopenull){thrownewIllegalStateException(No Scope registered for scope name scopeName);}try{ObjectscopedInstancescope.get(beanName,()-{this.beforePrototypeCreation(beanName);Objectvar4;try{var4this.createBean(beanName,mbd,args);}finally{this.afterPrototypeCreation(beanName);}returnvar4;});beanInstancethis.getObjectForBeanInstance(scopedInstance,name,beanName,mbd);}catch(IllegalStateExceptionex){thrownewScopeNotActiveException(beanName,scopeName,ex);}}}catch(BeansExceptionex){beanCreation.tag(exception,ex.getClass().toString());beanCreation.tag(message,String.valueOf(ex.getMessage()));this.cleanupAfterBeanCreationFailure(beanName);throwex;}finally{beanCreation.end();}}return(T)this.adaptBeanInstance(name,beanInstance,requiredType);}该方法总共分了两部分获取Bean和创建Bean。首先转换bean的名称String beanName this.transformedBeanName(name);处理别名、FactoryBean前缀如等得到最终的beanName。尝试从缓存中获取单例Bean依次检查一级缓存singletonObjects已经完成初始化的单例。二级缓存earlySingletonObjects提前曝光的半成品Bean。三级缓存singletonFactoriessingletonObjects用于存放单例bean实例的缓存即作用域为singleton的bean。当创建完一个bean后Spring会将其放入singletonObjects缓存中。在后续获取该bean时Spring会直接从该缓存中获取不再需要重新创建。earlySingletonObjects用于存放创建中的bean实例的缓存。在创建一个bean的过程中如果需要引用到该bean则会先从earlySingletonObjects缓存中获取。如果该缓存中不存在该bean的实例则会通过实例化工厂创建一个新的bean实例。singletonFactories用于存放创建中的bean实例的工厂缓存。在创建一个bean的过程中如果需要引用到该bean则会先从singletonFactories缓存中获取。如果该缓存中不存在该bean的工厂实例则会通过实例化工厂创建一个新的bean工厂实例。在后续获取该bean时Spring会从该缓存中获取bean工厂实例并通过该工厂创建新的bean实例。在以上三个缓存中earlySingletonObjects缓存和singletonFactories缓存的作用是相同的即存放创建中的bean实例。它们的区别在于earlySingletonObjects缓存存放的是已经创建但还没有完全初始化的bean实例而singletonFactories缓存存放的是bean实例工厂。if (sharedInstance ! null args null)如果从缓存中获取到单例bean并且命中无构造参数通过getObjectForBeanInstance()返回实际对象。BeanFactory parentBeanFactory this.getParentBeanFactory();获取父类对象工厂获取对象。if (!typeCheckOnly) { this.markBeanAsCreated(beanName); }将当前bean标记为已创建。String[] dependsOn mbd.getDependsOn();递归创建依赖。if (mbd.isSingleton()) {...} else if(mbd.isPrototype()){...}else{...}根据对象的同类型单例、原型、其他作用域request/session创建bean。

更多文章