简介
在之前的文章里,我们讨论过作为spring IOC容器实现里最底层的一部分:BeanWrapper。那里,我们主要了解如何从获取的元数据里来构造一个bean对象的过程。当然,从更广阔的角度来看,这个容器框架里需要的是能够构建一个bean对象的容器,我们可以通过它来方便的获取所需要的bean对象,而不是仅仅单独设置好的某一个对象。在spring框架里,要构造这么一个容器,就需要BeanFactory, ApplicationContext等一系列类的合作。在这里,我们结合它们的实现细节来分析探讨一下它的设计思想。
示例
在讨论它们的具体实现之前,我们先看一个示例。
首先,我们定义一个传统的工程,里面有对spring相关的依赖pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yunzero</groupId> <artifactId>springSample</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springSample</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java-version>1.8</java-version> <log4j.version>2.10.0</log4j.version> <spring.version>5.0.6.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>${project.artifactId}-${project.version}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>${java-version}</source> <target>${java-version}</target> </configuration> </plugin> </plugins> </build> </project>
然后我们定义一个类HelloWorld:
package com.yunzero; public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public void printHello() { System.out.println("Spring 5 : Hello ! " + name); } }
非常简单的一个类。然后再定义相关的xml配置文件applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloBean" class="com.yunzero.HelloWorld"> <property name="name" value="frank"/> </bean> </beans>
这里定义了需要设置的bean和它被注入的值。接下来就是一个运行的代码:
package com.yunzero; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld obj = context.getBean(HelloWorld.class); obj.printHello(); } }
运行程序的话,结果很简单,将输出如下的内容:
Spring 5 : Hello ! frank
我们都知道,程序之所以能够输出如下的结果,是因为在前面的配置文件里,我们设置了HelloWorld对象的name属性为frank。从一个实现者的角度来看的话,我们可以做一些简单的推测。因为在前面的xml文件里定义了<bean>的元素,它的id是helloBean,类型是com.yunzero.HelloWorld。所以,在后面的程序里,我们可以使用applicationContext.getBean方法获取到这个对象。在框架的内部,这个对象的构造肯定包含有解析配置文件,构建bean对象关系图等这么几个步骤。
而从后面的一些分析来看,我们可以确定,就是ApplicationContext这个类及相关的子类提供了一个运行时的环境用来保存相关的对象。
ApplicationContext
虽然我们在之前的一些材料里已经了解到,spring IOC容器的实现包含有3个层面的实现,从下到上是BeanWrapper, BeanFactory和ApplicationContext。我们这里先结合示例代码的使用情况来跟踪分析。既然前面提到过ApplicationContext能够提供对象的运行时环境,我们就看看它的详细实现代码。我们先来看一下spring里ApplicationContext相关的类结构:
这里的类结构非常庞大,我们在讨论到相关的部分的时候会一一看过来。虽然这里没有画出来ClassPathXmlApplicationContext类来,实际上它是继承了类AbstractXmlApplicationContext。现在我们先看看代码里new ClassPathXmlApplicationContext("applicationContext.xml")的实现:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
可见,前面我们调用的ClassPathXmlApplicationContext的构造函数本质上还是调用了一个统一的构造函数方法。里面还有若干个构造函数,也是代理使用了这同一个方法。
在这个方法里,它的实现主要集中在refresh方法里。前面的setConfigLocations方法只是将我们提供的String参数设置到声明的成员变量。我们重点看看refresh方法的实现。它的实现是在类AbstractApplicationContext里:
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); // 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 (BeansException ex) { 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. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
这个方法的实现可以说是整个容器实现的最核心部分。我们针对详细的细节一一看过来。
第2行代码使用了对象锁,将整段代码的逻辑给加锁,保证在同一个时刻,只有获取到该对象锁的线程才能执行上述的逻辑,这样可以避免在多线程执行的情况带来的混乱。
第4行的prepareRefresh方法的实现如下:
protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); }
这个方法的实现细节其实很简单,就是设置一些初始化的状态标记,比如closed, active等。而其中的initPropertySource方法的实现就是一个空的,具体的实现取决于后续的继承类的需要。而通过getEnvironment方法验证当前需要的property文件是否可以解析。所以,整体来说,这个方法就相当于是一个准备工作。
在前面refresh方法里的第7行,obtainFreshBeanFactory返回一个ConfigurableListableBeanFactory。这个类是系统里面提供的一个默认的BeanFactory的实现,我们在后面会详细的讨论。这个方法的实现细节如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
其中refreshBeanFactory的实现在类AbstractRefreshableApplicationContext里:
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); } }
它首先判断BeanFactory是不是已经存在了,如果有的话,通过destroyBeans和closeBeanFactory来释放这些创建的bean对象以及BeanFactory的空间。它们的实现主要就是通过将指向的BeanFactory对象设置为null,并事先将相关的Bean对象存储空间都清空。
接着在try块里,createBeanFactory的实现则很直接,就是创建了一个DefaultListableBeanFactory:
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
而customizeBeanFactory主要是设置创建的beanFactory的几个基本属性:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
里面还有一个loadBeanDefinitions方法,它本身是一个定义的虚方法,由继承的类来实现。在从ApplicationContext到ClassPathXmlApplicationContext的继承类体系里,AbstractXmlApplicationContext提供了一个针对读取xml文件的实现:
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); } 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); } }
获取最终的BeanDefinition实际上是通过一个XmlBeanDefinitionReader来实现的。为什么这里要引入BeanDefinition这个概念呢?因为在spring框架里,通过将定义的bean信息抽象成一个BeanDefinition的类型。这样,在前面示例里xml文件里的内容就是在这里被读取和解析的。我们后面也会针对这一块进行进一步的分析。为了讨论上述obtainFreshBeanFactory这个方法的过程,结果要扯出这么多的方法和对象来。总结一下这个方法的过程,其实它们的交互过程如下图:
我们接着看第10行的prepareBeanFactory,它主要是配置beanFactory的classLoader和postProcessor等信息。这部分很简单。
接着是第14行的postProcessBeanFactory,它的默认实现为空,有必要的情况下在一些ApplicationContext的实现里会实现这个方法。
第17行的invokeBeanFactoryPostProcessors通过PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法来处理beanFactoryPostProcessor。
后面是第20行的registerBeanPostProcessors方法,它是在bean创建的过程中注册processor的。它也是通过PostProcessorRegistrationDelegate的registerBeanPostProcessors来实现的。由于这部分和IOC的设计关系不是很紧密,具体的实现就不详细分析了。
第23行的initMessageSource用来设置它的messageSource变量。这个东西是用来解析消息用的。主要用于消息的国际化,比如同样的消息内容针对不同国家语言的显示。
后面第26行的initApplicationEventMulticaster方法是用来设置ApplicationEvent的组播的。在ApplicationContext里有一个对事件的支持。针对一些特定的事件,我们可以定义相关的listener。它其实就是相当于一个observer pattern的实现,当然,这也是ApplicationContext里的一个特性。默认的情况下这个成员变量会被设置成SimpleApplicationEventMulticaster对象。
接着的第29行的onRefresh方法也是一个空的实现。后续的继承类如果需要的话可以通过覆写它来提供自己特定的实现。
第32行的registerListeners方法主要将一些ApplicationListener注册到applicationEventMulticaster里。并没有什么特殊的。
等到第35行的finishBeanFactoryInitialization方法时,基本上beanFactory初始化的过程就已经差不多了。这个方法主要设置这时候不能再更新bean definition等元数据信息了。
第38行的finishRefresh方法基本上相当于是做一个收尾工作:
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
从代码里就可以看到,主要就是这么几个步骤,一个是清除一些resource cache。然后初始化一些lifecycleprocessor。因为在初始化的不同阶段对应一些事件通知机制,这里会调用相关的事件触发方法。然后再通过ApplicationEventMulticaster来发布消息。
BeanDefinition & BeanDefinitionReader
在前面的AbstractRefreshableApplicationContext里,我们分析了refreshBeanFactory方法。里面有一个方法的loadBeanDefinitions的实现在这里讨论。那里的loadBeanDefinitions方法的具体实现是在类XmlBeanDefinitionReader里:
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<>(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(); } } }
上面这部分代码其实还是比较好理解的,它的主要逻辑在try块里,通过获取当前resource的inputStream,然后通过doLoadBeanDefinitions方法来加载解析文件。这里一个比较有特点的地方就在于它是通过一个Resource接口返回InputStream的方式来统一定义读取的数据源。这样可以根据不同的数据源来进行扩展,但是所有的使用者都是通过面向抽象的接口来操作。标准的OO原则。
再来看看doLoadBeanDefinitions方法的细节:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); 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); } }
这么长的方法里主要的业务逻辑就在于两个方法,doLoadDocument和registerBeanDefinitions。doLoadDocument方法主要是通过java默认的api来加载xml文件,将加载的文件DOM结构构造成Document对象。它的详细实现是在DefaultDocumentLoader里:
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
我们再来看看registerBeanDefinitions的实现:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
这部分的逻辑是通过创建一个BeanDefinitionDocumentReader对象,然后调用它的registerBeanDefinitions来实现详细的逻辑。我们继续跟进去看看它的实现。这个具体的实现方法是在类DefaultBeanDefinitionDocumentReader,它的实现如下:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
这里仅仅是通过获取到文档的根元素,然后在doRegisterBeanDefinitions里继续分析里面的子元素:
protected void doRegisterBeanDefinitions(Element root) { // 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 = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
这个方法里的第11到第24行主要是处理xml文件里有profile属性的情况,用于在多个部署环境的配置处理。而后面的3个方法里,preProcessXml和postProcessXml的方法实现为空,由后续的子类根据需要来继承覆写。详细的解析放在parseBeanDefinitions里:
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); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
在这个方法里,它通过遍历它的所有子节点对元素进行分别处理。如果是xml文件里的默认元素,像bean等元素,就通过parseDefaultElement方法来处理。如果是一些自定义的元素,则放到parseCustomElement方法里处理。其中parseDefaultElement是我们最常用到的。它的实现如下:
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); } }
这里的实现根据nodeName来区分,如果nodeName是import,表示我们在这个文件里还要导入别的xml bean定义文件,则需要在importBeanDefinitionResource方法里导入新的文件。而如果nodeName是alias,表示这个元素是另外一个元素的别名,则通过processAliasRegistration来处理,这个方法AliasRegistry接口的一个实现,将有相同别名的元素放到一个HashMap里。如果beanName是嵌套的beans元素,表示我们需要进一步解析里面的元素,这里通过嵌套的调用doRegisterBeanDefinitions来实现。如果里面的nodeName是bean,表示我们要解析处理一个定义的bean对象,这里则通过processBeanDefinition方法来处理。它的细节比较重要,这里详细列出来:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 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)); } }
这部分的代码大部分还是起到一个代理的作用,它通过BeanDefinitionParseDelegate来解析BeanDefinition里的元素得到BeanDefinitionHolder对象,然后通过registerBeanDefinition来注册这个beanDefinition,详情见parseBeanDefinitionElement:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
这部分的代码主要处理元素的id, name等属性,对于里面有构造函数以及参数类型的处理则放在另外一个重载的parseBeanDefinitionElement里。可见,这个处理的过程非常繁琐复杂。针对这个loadBeanDefinitions方法牵涉到的过程,我们总结一下她们的交互图,这样有利于整理前面的这些代码。详细的图如下:
这样,到此为止我们就把通过读取配置文件来构造BeanDefinition的过程简单整理了一下。前面费了那么多劲分析的过程里,最终在spring里是定义成BeanDefinition的类型。那么,这个类型是个什么样的定义呢?它相关的类型结构如下图:
在这个结构图里主要继承和定义的接口是AttributeAccessor和BeanMetadataElement。AttributeAccessor比较简单,主要就是定义一个通用的访问属性的接口。主要的定义方法如下:
public interface AttributeAccessor { void setAttribute(String name, @Nullable Object value); @Nullable Object getAttribute(String name); @Nullable Object removeAttribute(String name); boolean hasAttribute(String name); String[] attributeNames(); }
有点像一个典型的增删查改的接口方法。继承这个接口的BeanDefinition增加了更多特定于一个Bean相关的方法,主要有parentName, beanClassName, scope, lazyInit, dependsOn, autowireCandidate, primary, factoryBeanName, factoryMethodName, propertyValues, isSingleton, isPrototype, isAbstract这些在文件里用来设置的主要属性。 绝大多数都是各种get, set方法。
所以,从这个角度来看,BeanDefinition无非就是对从配置里读取到的内容的一个映射。起到一个记录Bean对象生成之前必要属性的效果。没什么特殊的。
在之前分析源代码的时候,我们也已经看到,BeanDefinitionReader被用来读取文件并映射成BeanDefinition对象。它的相关结构如下图:
在这个图里,BeanDefinitionReader主要的方法是loadBeanDefinitions。而从实现里也可以看到,它间接的通过BeanDefinitionDocumentReader来读取各种document,包括xml文件类型的等等。
BeanFactory
在进一步讨论BeanFactory之前,我们看看前面的讨论。这些讨论都是基于前面程序里的示例代码来进行的。而这么多的流程和实现,无非只是覆盖了前面
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
这一行代码的实现细节。而在后面一行里,有context.getBean()的方法。这个方法的实现细节如果我们细究下去的话,就会发现它主要就是通过BeanFactory相关的类实现的。BeanFactory是一个接口,它的定义就是为了要求所有的实现里实现这个接口来获取和构造具体的Bean对象。而Bean对象就是我们最终获得的构造出来的结果对象,也是我们程序里最终直接起作用和代码打交道的对象组了。
我们先看一下它相关的类结构,如下图:
除了BeanFactory定义了一些基本的bean操作方法之外,后续继承的接口像ListableBeanFactory用来支持里面的对象是可以列举的。而HierarchicalBeanFactory用来表示里面的对象是有层级继承关系的。而AutowireCapableBeanFactory表示支持里面的对象可以支持Autowire annotation,可以通过它来组织和构造对象及之间的关系。通过之前ApplicationContext的类图结构,我们看到ApplicationContext也继承了接口ListableBeanFactory和HierarchicalBeanFactory。所以,它的具体实现里就支持bean对象的列举和层级继承关系。
从上图中还看到一个地方,就是所有的接口和抽象类最后都有一个默认的实现:DefaultListableBeanFactory。它在很多地方都被用到。
我们先从前面的context.getBean()方法里继续跟进它的实现细节。BeanFactory接口里主要定义的方法有如下几个:
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
其中最常用的方法就是Object getBean(String name)。它的实现主要是在AbstractBeanFactory里:
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> 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.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 = 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 { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } 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.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
这里面所有的getBean方法最终都是通过doGetBean方法实现的。doGetBean方法的实现看起来比较长,我们这里相对里面的细节稍微整理一下。
第9行的代码主要是生成beanName,主要这里要考虑FactoryBean,它是以字符&为开头命名的,所以需要处理这种情况。
第13行的getSingleton方法的实现主要是读取已有的ConcurrentHashMap里是否存在这个bean对象了,否则通过singletonObjectFactory这个HashMap来获取对象。之所以这里要考虑从这些缓存的Map里取,是因为在前面ApplicationContext初始化的时候,有个地方预先把一些singleton对象放到里面了。这里的实现是AbstractApplicationContext里的方法finishBeanFactoryInitialization。在这个方法里有一行:
beanFactory.preInstantiateSingletons();
它会预先加载一部分bean对象。我们在后面会详细分析它。
接下来看第36行到51行的过程,它主要是判断,如果当前beanFactory里没找到对应的BeanDefinition,则通过它的父beanFactory来继续查找和构建对象。
第57行到第77行的部分则是获取该bean对象定义里的dependsOn属性,如果有的话,先构造它所依赖的对象,然后再尝试构造这个bean。
第81行到第95行处理bean scope是singleton的情况。如果定义的是singleton,则通过createBean方法构造这个bean对象,并赋值给sharedInstance。
第97行到107行处理bean scope是prototype的情况。它通过将beanName加入到一个ThreadLocal的变量里,并将beanName加入到一个集合里。
第110行到134行处理bean scope为其他的情况。因为我们一般的应用里会仅仅使用到singleton和prototype两种情况,但是在一些web应用里,还会有request, session, application不同范围的情况。所以这里也要采用一定的方法来支持。
我们先不着急把整个过程给描述出来,先看一下之前搁置的beanFactory.preInstantiateSingletons方法。它的实现在类DefaultListableBeanFactory里:
public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } // 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<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
这部分代码里要点主要有3个部分,首先是第12行的getMergedLocalBeanDefinition,这里主要是通过一些beanName来得到对应的BeanDefinition,然后和本地的benDefinition进行合并。因为有的Bean和现有的是一种继承的关系。这样可以将多个bean的定义给合并成一个统一的结构。第14行到第31行则是用来处理FactoryBean的情况。因为这是通过某种factory方法构造的对象,所以它的处理方式需要通过调用factoryBean的方法来返回bean对象。正常的情况下,则是直接调用getBean方法。
第40行到后面的部分则处理一些回调方法的情况。比如afterSingletonsInstantiated等。
从上面的讨论过程,我们可以整理出一个如下的顺序图:
总的来说,getBean的过程就是i通过先合并本地的BeanDefinition,然后再通过ObjectFactory的实现来返回这个bean。而在前面doGetBean方法里有调用过createBean方法,这就是最终提供和创建bean的方法。
我们结合源代码再跟进一下createBean方法的实现过程。
它的实现在类AbstractAutowireCapableBeanFactory里:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
这一大段代码在40行之前主要是做一些创建bean对象之前的准备工作,比如说通过resolveBeanClass方法来验证给定beanName的class和BeanDefinition已经构建好。而resolveBeforeInstantiation方法则是调用一些beanPostProcessor的回调方法。真正的实现细节在doCreateBean方法里。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } 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, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); 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<>(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); } return exposedObject; }
这段代码里就是执行创建bean和相关设置的具体逻辑了。首先它判断相应的beanInstance是否已经存在了,如果不存在,则调用第10行的createBeanInstance。createBeanInstance这个方法选择合适的初始化策略来构造bean对象。该方法的实现如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable 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()); } Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } if (mbd.getFactoryMethodName() != null) { 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); } // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }它主要通过传入的RootBeanDefinition来确定某些参数是否被设置了,然后调用对应的构造对象方法。比如它的FactoryMethodName如果不为空的话,则通过factoryMethod方法来构造这个对象。如果instanceSupplier不为空的话,则通过obtainFromSupplier方法返回构造对象。而对于默认的构造方式,则是通过instantiateBean方法来实现的:
相关推荐
3. BeanFactory与ApplicationContext:BeanFactory是最基础的容器,负责管理Bean的生命周期和依赖关系;ApplicationContext不仅包含BeanFactory的功能,还提供国际化、资源加载、事件发布等更全面的企业级服务。 4....
主要有两种类型的容器:BeanFactory和ApplicationContext。 3. **面向切面编程(Aspect-Oriented Programming,AOP)**:Spring AOP允许开发者定义“切面”——跨越多个类的行为或责任。通过切点(Pointcut)和通知...
主要有两种类型的容器:BeanFactory和ApplicationContext,后者提供了更多的企业级功能。 3. **Bean**:在Spring中,一个Bean通常代表一个Java对象,由Spring容器管理其生命周期。Bean可以通过XML配置、注解或Java...
- **IoC 容器的实现**:查看 BeanFactory 和 ApplicationContext 如何加载和管理 Bean,以及如何解析 XML 或注解配置。 - **AOP 实现**:研究 AspectJ 注解和织入过程,理解切点表达式和通知的工作原理。 - **MVC ...
它有两种主要类型:BeanFactory和ApplicationContext,后者提供了更多企业级服务。 4. **数据访问集成(DAO)**:Spring提供了对多种数据库访问技术的支持,包括JDBC、ORM框架(如Hibernate、MyBatis)和O/R ...
2. **Spring Core Container**:Spring的核心容器包括BeanFactory和ApplicationContext,它们负责管理对象的生命周期和依赖关系。BeanFactory是Spring的基础,而ApplicationContext则提供了更多的企业级服务,如消息...
1. Core Container:包含了Bean工厂(BeanFactory)和ApplicationContext,是Spring框架的基础。BeanFactory负责管理应用对象的生命周期和依赖注入,而ApplicationContext则提供了更多的企业级服务,如事件传播、...
接着,书中将详细讲解Spring的核心模块,如Core Container(核心容器),包括BeanFactory和ApplicationContext,它们是Spring框架的基础。此外,作者还会探讨AOP(Aspect-Oriented Programming,面向切面编程)模块...
Spring框架是中国最流行的Java企业级应用开发框架之一,它由Rod Johnson在其著作《Expert One-on-One J2EE Design and Development》中首次提出。Spring的核心设计理念是依赖注入(Dependency Injection,DI)和面向...
1. **Spring Core Container**:这是Spring框架的基础,包含Bean工厂(BeanFactory)和应用上下文(ApplicationContext)。BeanFactory负责管理应用对象的生命周期和依赖关系,而ApplicationContext则在BeanFactory...
### Introducing Spring: the dependency injection container(第1章:介绍Spring:依赖注入容器) - **Spring框架概述**:Spring是一个开源框架,旨在简化Java应用开发。它提供了全面的基础架构支持,让开发者...
Spring容器是实现IoC和DI的基础,它可以是BeanFactory或ApplicationContext。容器负责管理对象的生命周期,创建、初始化、配置以及管理对象间的依赖关系。 **IoC类型**: Spring支持两种IoC容器类型:BeanFactory和...
2. **容器(Container)**:Spring框架中的容器负责创建和管理对象,主要有两种容器:BeanFactory和ApplicationContext。BeanFactory是基础,而ApplicationContext提供了更多的企业级服务,如国际化、事件传播等。 ...
- **Core Container**:核心容器,包括BeanFactory和ApplicationContext,它们是Spring框架的基础,负责管理对象的生命周期和依赖注入。 - **Data Access/Integration**:数据访问/集成,支持JDBC、ORM(Object-...
2. **容器(Container)**:Spring容器负责创建、配置和管理对象。有两种主要的容器:BeanFactory和ApplicationContext。BeanFactory是最基础的容器,而ApplicationContext提供了更多的企业级功能,如消息支持和国际...
- **Spring 容器**:探究 BeanFactory 和 ApplicationContext 的区别,以及如何通过它们管理对象的生命周期。 - **数据访问**:了解 Spring 如何整合各种 ORM 和 OXM 框架,以及如何实现数据访问层的事务管理。 ...
3. **核心容器**:详细解析了BeanFactory和ApplicationContext,这两个是Spring管理bean的核心组件。还可能涉及到bean的生命周期和作用域。 4. **数据访问**:涵盖了Spring对各种数据库访问技术的支持,如JDBC、ORM...
- Spring MVC是Spring框架的一部分,它提供了一种优雅的MVC实现,分离了模型、视图和控制器,允许开发者专注于业务逻辑而不必关心视图的实现。此外,Spring MVC支持数据验证、模型绑定、异常处理等特性,提高了Web...
1. **Spring Core Container**:这是Spring框架的基础,包括Bean工厂(BeanFactory)和应用上下文(ApplicationContext)。BeanFactory负责对象的创建、配置和管理,而ApplicationContext在BeanFactory的基础上增加...
有两种主要类型的容器:BeanFactory和ApplicationContext,后者提供了更多企业级功能,如消息源和国际化支持。 4. **bean的声明和管理**:在Spring中,业务逻辑组件通常被定义为beans。开发者可以在XML配置文件中...