一、簡介
spring容器是整個spring框架的核心,通常我們說的spring容器就是bean工廠,bean工廠負責創建和初始化bean、裝配bean並且管理應用程序中的bean.spring中提供了兩個核心接口:BeanFactory和ApplicationContext,ApplicationContext是BeanFactory子接口,它提供了比BeanFactory更完善的功能.
二、ApplicationContext的工作原理
先建立一個新的java項目,搭建好spring的開發環境.然后啟動spring的容器,如下面的代碼:
public class Demo { public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml"); } }
spring容器啟動時,會完成兩個重要的工作:加載bean的定義信息(BeanDefinition)以及初始化所有單例bean,在初始化bean的過程中注入bean的依賴.bean的定義信息是指:bean的基本屬性,例如完整類名,是否單例等等,其實就是<bean id="" class="" scope="">元素的那些屬性.在創建bean時需要用到這些屬性,所以必須要先加載bean以及它的定義信息.
先說spring容器加載bean的定義信息的實現原理,spring中有兩種配置bean的方法:
- 使用配置文件配置bean,需要在<bean>元素中聲明bean的信息;spring容器啟動時,會讀取配置文件並進行解析,這種情況下,只要解析bean元素就可以獲取bean的beanName和它的定義信息.
-
使用注解配置bean,需要在配置文件中配置bean的路徑,例如:<context:component-scan base-package="cn.spring"/>,這樣容器啟動時就會掃描cn.spring包以及子包下面的所有類,如果類上有@Controller 或者 @Service 或者@Repository或者@Component注解,spring就會加載這些類的定義信息;這里就會有幾個問題,第一個問題是如何獲取base-package的子包以及包下的所有類?spring的做法是將包名轉化成文件系統中的路徑,然后traverse獲取該目錄下的所有.class文件,非常巧妙的一個解決方案!接下來的問題是如何從.class文件中獲取bean的定義信息呢?有兩種方式,第一種就是把通過.class文件的路徑獲取該類的包名,然后通過類加載器加載該類獲取它的定義信息,第二種方式是用asm框架從class文件中直接讀取類的定義信息。spring用的是第二種方式,個人覺得spring選擇第二種方式是有以下幾個原因,其一,可能需要對class文件進行增強處理,也就是在class文件中增加一些新的指令,在生成代理時可能會需要這樣做;其二,反射無法獲取類完完全全的信息(例如:方法的參數名稱),其三,反射的性能問題;
接下來,就是容器初始化單例bean的過程:
spring容器在加載完所有bean的定義信息以后,會有一個refresh()操作,在refresh容器過程中完成兩個重要的操作,第一個就是創建所有單例bean,第二個就是裝配這些創建bean(注入它們所需要的依賴);
因為前面的操作已經加載了所有bean的定義信息,並且維護了一個<beanName,BeanDefinition>對應關系的Map,遍歷Map,就可以取得每個bean的定義信息,從bean的定義信息可以知道bean是否是單例,如果是單例的,下一步就會根據bean的定義信息來決定bean實例的創建策略,如果配置了bean的factory-method,就調用factory-method創建bean實例,如果沒有配置factory-method,默認會調用bean的無參構造函數創建bean實例.
創建bean實例之后的工作就是裝配bean,現在已經拿到了bean實例,如果bean是在配置文件中配置的,此時就會先把配置文件中配置的屬性賦值給bean實例上對應的屬性;而后由bean的后處理器(BeanPostProcessor)完成bean實例其他屬性(通過注解配置的)的注入.如果bean是通過注解進行配置,這時直接就會由bean的后處理器完成bean的裝配.完成bean裝配的后處理器的工作原理:遍歷bean對象的字段和方法,根據字段和方法上應的注解完成相對應的注入操作.
在裝配bean的過程中會出現一個問題:A依賴B,裝配A的時候B的實例還沒有創建,spring解決這個問題的辦法是:先創建B對象,裝配好bean,然后把B注入A,繼續完成A的裝配.
三、容器初始化過程的源碼分析
我們從ApplicationContext的構造函數開始,如下代碼:
/** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. --->加載所有bean的定義信息,創建所有單例bean * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */ public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent);
// 解析給定的配置文件,完成加載所有bean的定義信息的操作 setConfigLocations(configLocations); if (refresh) {
// refresh容器,完成創建單例bean的操作 refresh(); } }
構造方法的注釋上寫的so nice.接下來,看加載bean的定義信息的過程,setConfigLocations()是在父類中實現的,接收到配置文件以后,容器開始解析配置文件.經過一系列的調用,會調用org.springframework.beans.factory.xml.XmlBeanDefinitionReader的doLoadBeanDefinitions(),到這里終於看到Document,下面是該方法的源碼:
/** * 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 */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); // 取得Document對象 Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); // 從Document對象中解析bean的定義信息 return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; }
// ...各種異常的處理 }
registerBeanDefinitions()又會經過一系列的檢查和處理,然后調用
/** * Register each bean definition within the given root {@code <beans/>} element. * @throws IllegalStateException if {@code <beans profile="..."} attribute is present * and Environment property has not been set * @see #setEnvironment */ protected void doRegisterBeanDefinitions(Element root) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { Assert.state(this.environment != null, "environment property must not be null"); 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 = createHelper(readerContext, root, parent); preProcessXml(root); // 重點部分,解析bean的定義信息 parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ 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)) { parseDefaultElement(ele, delegate); // 重點:解析bean元素 } else { delegate.parseCustomElement(ele); // 重點:解析其他元素,例如:<context<context:component-scan> or <annotation:config/> } } } } else { delegate.parseCustomElement(root); } }
到這里,終於到了關鍵的地方,如果bean是在配置文件中配置的,由parseDefaultElement(ele, delegate)處理bean元素的解析,如果是注解配置,parseCustomElement(ele)會掃描包下的class文件,並完成解析.我們先看配置文件中bean元素的解析方式。
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)) { // recurse doRegisterBeanDefinitions(ele); } } /** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 獲取bean的定義信息,用BeanDefinitionHodler對象封裝 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance.---》關鍵,將bean的定義信息保存到容器 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)); } }
接下來就是調用org.springframework.beans.factory.support.BeanDefinitionReaderUtils的registerBeanDefinition()保存bean定義信息到容器的方法了.
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ 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 aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
ok,來看最終的保存代碼:
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
/** List of bean definition names, in registration order */
private final List<String> beanDefinitionNames = new ArrayList<String>();
保存bean定義信息的方法:
//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // 保存bean定義信息,線程同步 synchronized (this.beanDefinitionMap) {
// 判斷當前bean的定義信息是否已經保存 Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else {
// 保存beanName this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; }
// 保存beanName和bean的定義信息到Map this.beanDefinitionMap.put(beanName, beanDefinition);
resetBeanDefinition(beanName);
}
}
上面就是spring解析配置文件中的bean定義信息,然后保存beanName和bean定義信息到Map中.這個過程主要就是xml的解析.接下來我們看spring是如何解析注解方式配置的bean.回到parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法,現在重點關注:delegate.parseCustomElement(ele)方法.如果我們在配置文件用<context:component-scan base-package="">方式來指定自動掃描的包,之后就會調用org.springframework.context.annotation.ComponentScanBeanDefinitionParser的parse().下面是parse()方法的源代碼:
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 解析<context:component-scan元素,獲取base-package String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // Actually scan for bean definitions and register them. ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//重點: 掃描basePackage下所有的class文件,讀取bean的定義信息 Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
重點關注scanner.doScan(basePackges)方法,該方法完成整個核心操作--->根據包名獲取包下所有的class的定義信息.直接看org.springframework.context.annotation.ClassPathBeanDefinitionScanner的scan():注意,看源碼時一定要多關注注釋,例如下面方法上的注釋就非常有意義.
/** * Perform a scan within the specified base packages, * returning the registered bean definitions. * <p>This method does <i>not</i> register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); for (String basePackage : basePackages) { // 遍歷每一個basepackages
// 1.獲取basePackage下bean的定義信息 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) {
//2.根據掃描的信息,解析bean的一些定義信息 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder);
// 3.將bean的定義信息添加到容器中 registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
第1個步驟我們核心關注點,它完成從文件系統中讀取class文件的操作,第3個步驟在之前已經說了,就是保存bean的定義信息到容器的DefaultListableBeanFactory的beanDefinitionMap 中.重點關注第1個步驟,看findCandidateComponents()的源代碼:
/** * Scan the class path for candidate components. * @param basePackage the package to check for annotated classes * @return a corresponding Set of autodetected bean definitions */ public Set<BeanDefinition> findCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + this.resourcePattern;
// 1.獲取包下的class文件路徑,例如E:\Program Files (x86)\MyEclipse10\workplace2\spr\bin\cn\jack\domain\User.class,
// 每一個class文件的路徑封裝成Resource對象. Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try {
// 2.使用asm框架讀取class文件,獲取類的定義信息 MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); }
//3.返回benadefinition集合 return candidates; }
第1個步驟主要是解析文件路徑,然后遍歷文件夾獲取每個class文件的地址;第2個步驟用asm框架來讀取class文件獲取類的信息封裝成BeanDefinition對象.
第2個步驟最后調用的是org.springframework.core.type.classreading.SimpleMetadataReader的構造函數,下面是該類的部分源代碼:
final class SimpleMetadataReader implements MetadataReader { private final Resource resource; private final ClassMetadata classMetadata; private final AnnotationMetadata annotationMetadata; SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException { InputStream is = resource.getInputStream(); ClassReader classReader = null; try {
// asm框架讀取class文件 classReader = new ClassReader(is); } finally { is.close(); } // 采用訪問者模式來獲取class類信息 AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader); classReader.accept(visitor, true); this.annotationMetadata = visitor; // (since AnnotationMetadataReader extends ClassMetadataReadingVisitor) this.classMetadata = visitor; this.resource = resource; }
ClassReader是asm框架中核心類,具體用法可以參考asm的官網.
上面說的過程就是spring容器加載bean定義信息的過程.過程很長,但實現原理卻並不復雜.
2. 初始化單例bean的過程
上面分析了spring容器加載bean定義信息的過程,接下來分析bean的初始化以及創建bean的過程.回到ApplicationContext中的構造函數,入口為refresh().refresh方法在父類中實現的。下面是AbstractApplicationContext類refresh()方法的源代碼:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 線程同步 // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); 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);//注冊bean的后處理器 // 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);// 重點,注釋寫的so nice,初始化所有單例bean // 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; } } }
后處理器是一種特殊bean,用於完成一些自身操作.
容器后處理器:對容器本身進行處理,在容器實例化其他任何Bean之前讀取配置文件的元數據並可能修改這些數據.PropertyPlaceholderConfigurer就是一個容器后處理器,用於完成beans.xml中引入其他配置文件中內容操作.
Bean后處理器:即當Spring容器創建完Bean實例之后對bean進行一些處理,例如:完成bean的裝配等操作。
回到refresh()方法,重點關注:finishBeanFactoryInitialization(beanFactory);這個方法會調用DefaultListableBeanFactory.preInstantiateSingletons方法.
public void preInstantiateSingletons() throws BeansException { if (this.logger.isInfoEnabled()) { this.logger.info("Pre-instantiating singletons in " + this); } synchronized (this.beanDefinitionMap) { // 線程同步 // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); for (String beanName : beanNames) {// 遍歷beanNames RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//單例非延遲實例的bean if (isFactoryBean(beanName)) { // 工廠bean.FactoryBean接口的子類 final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { public Boolean run() { return ((SmartFactoryBean) factory).isEagerInit(); } }, getAccessControlContext()); } else {//普通bean isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); // 從容器中獲取bean,如果沒有創建,並完成裝配 } } } } }
getBean(beanName)方法會調用doGetBean方法.這是個很關鍵的地方,切記注釋很重要
/** * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean * @throws BeansException if the bean could not be created */ @SuppressWarnings("unchecked") protected <T> T doGetBean( final String name, final Class<T> requiredType, 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) { //bean已創建,調用方法返回該bean if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } }
//如果是工廠bean,則返回beanFactory.getObject(),普通bean直接返回sharedInstance bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //bean未創建 // 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();
// 檢查父容器是否已經創建該bean,有則從父容器獲取bean返回 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } 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 dependsOnBean : dependsOn) { getBean(dependsOnBean); registerDependentBean(dependsOnBean, beanName); } } // Create bean instance.---》創建單例bean if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args);// ---> 創建bean的方法 } 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 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // 創建原型bean,scope="prototype" // 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 '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory() { public Object getObject() throws BeansException { 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); } } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } }
// 返回bean return (T) bean; }
createBean(beanName, mbd, args)方法會調用doCreateBean()完成bean的創建工作,源代碼如下:
/** * Actually create the specified bean. Pre-creation processing has already happened * at this point, e.g. checking <code>postProcessBeforeInstantiation</code> callbacks. * <p>Differentiates between default bean instantiation, use of a * factory method, and autowiring a constructor. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. This parameter must be <code>null</code> except in this case. * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created * @see #instantiateBean * @see #instantiateUsingFactoryMethod * @see #autowireConstructor */ protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) {
// 1.創建bean的包裝類,裝飾設計模式 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. 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() { public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try {
//2.裝配bean populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { 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."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } //3.返回 return exposedObject; }
首先看第1個步驟,這個步驟中會創建bean實例和bean的包裝類,這里使用了裝飾設計模式.創建bean的實例過程比較簡單,如果配置bean時指定了bean的創建方法 factory-method,就用factory-method創建bean實例,默認會使用無參構造函數創建bean實例.這部分重點關注裝配bean的過程.
/** * Create a new instance for the specified bean, using an appropriate instantiation strategy: * factory method, constructor autowiring, or simple instantiation. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @return BeanWrapper for the new instance * @see #instantiateUsingFactoryMethod * @see #autowireConstructor * @see #instantiateBean */ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // Make sure bean class is actually resolved at this point. Class beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } if (mbd.getFactoryMethodName() != null) {// 使用工廠方法創建bean,<bean factory-method=""> return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // Need to determine the constructor... Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 用默認的構造函數創建bean,反射獲取構造函數,constructor.newInstance()創建bean. // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }
現在來看裝配bean的過程,這個過程完成注入bean的依賴對象,如果bean是在配置文件配置的,則把從xml中解析出來的屬性注入給bean實例,如果是用注解配置的依賴(@Resource 或者@AutoWired),則會解析bean的字段或者方法上的注解,根據這些注解找到對應的依賴,如果依賴對象已經創建,就直接注入依賴,否則,先創建依賴對象,在完成注入操作.
/** * Populate the bean instance in the given BeanWrapper with the property values * from the bean definition. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @param bw BeanWrapper with bean instance */ protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) { PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) { if (!pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } } // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { return; } // 根據beanName或者type完成自動裝配 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); // 調用bean后處理器 if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 重點:獲取bean要裝配的屬性和屬性值 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } // 給bean的屬性賦值 applyPropertyValues(beanName, mbd, bw, pvs); }
InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,能在bean初始化前后對bean進行處理.InstantiationAwareBeanPostProcessor有以下幾個子類:
@Resource注解注入依賴的工作就是由CommonAnnotationBeanPostProcessor完成的.下面是該類postProcessPropertyValues()的源碼:
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { //1.根據bean的字節碼,遍歷所有的字段和方法,獲取需要注入的字段或者方法 InjectionMetadata metadata = findResourceMetadata(bean.getClass()); try {
//2.從容器中查找依賴對象,並賦值給相應的字段,完成bean的裝配 metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; }
第1個步驟主要就是根據字節碼獲取所有字段和方法,然后遍歷查找有@Resource注解的字段或方法以及依賴bean的beanName,第2個步驟從容器中依賴對象的beanName(@Resource的name屬性值),如果容器中沒有該依賴對象就創建,有的話就直接獲取,並賦值給bean的屬性.這樣,就通過bean的后處理器完成了bean的裝配過程.
到這里,容器的啟動過程就完成了,此時就可以對外提供服務了.上面就是本人對spring容器部分源碼學習的一些總結.日后,了解更多會不定時更新上來!