目录

  • 前言
  • 何时解析
    • 测试类
    • `ClassPathXmlApplicationContext` 的构造器
    • `refresh()` 方法
  • `obtainFreshBeanFactory()` 方法
    • `refreshBeanFactory()` 方法
      • `destroyBeans()` 方法(重点)
      • `loadBeanDefinitions()` 方法(重点)
        • 进入到 `loadBeanDefinitions()` 方法中
        • `reader.loadBeanDefinitions(configLocation)` 方法
        • `loadBeanDefinitions(resources)` 方法
        • `loadBeanDefinitions(resource)` 方法
        • `doLoadBeanDefinitions()` 方法
        • `registerBeanDefinitions()` 方法(注册 `bean` 信息)
        • `doRegisterBeanDefinitions()` 方法
        • `parseBeanDefinitions()` 方法
  • `obtainFreshBeanFactory()` 方法总结
    • `obtainFreshBeanFactory()` 方法流程总结

前言

一直以来,只是知道 Spring 会解析所有的配置文件(通常我们会放在 resources 目录下),然后将从配置文件中解析到的 bean 定义封装成 BeanDefinition,加载到 IOC 容器中。而不知道其内部是如何解析,执行的,本篇文章将予以揭秘

何时解析

要知道 spring 何时去解析配置文件,我们可以断定是在 IOC 容器启动时,那么我们可以根据 IOC 容器启动流程进行找寻

测试类

public class TransactionTest_2 {public static void main(String[] args) {/* 初始化启动 spring ioc 容器 */ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");/* 从 spring ioc 容器中获取一个 bean */ProductInfoService productInfoService = (ProductInfoService) applicationContext.getBean("productInfoServiceImpl");System.out.println("拿到的Bean为:" + productInfoService);}
}

在第五行代码处打上断点,DEBUG 模式去调试

ClassPathXmlApplicationContext 的构造器

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();}
}

它的核心方法肯定就在 refresh() 方法里面,实际上它调用的是抽象类AbstractApplicationContextrefresh()

refresh() 方法

@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {/*** 刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验*/prepareRefresh();// 该方法会解析所有 spring 配置文件(通常我们会放在 resources 目录下)// 将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();/*** 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等* 设置SPEL表达式#{key}的解析器* 设置资源编辑注册器,如PerpertyEditorSupper的支持* 添加ApplicationContextAwareProcessor处理器* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去*/prepareBeanFactory(beanFactory);try {/*** 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess* 在当前上下文使用的Bean容器BeanFactory的标准初始化完成后对其做一些修改。此时* 所有的Bean definition都已经加载但是还没有 Bean 被创建*/postProcessBeanFactory(beanFactory);/*** 实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor* 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法*/invokeBeanFactoryPostProcessors(beanFactory);/*** 注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法*/               registerBeanPostProcessors(beanFactory);// 初始化上下文中的资源文件,如国际化文件的处理等initMessageSource();// 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisherinitApplicationEventMulticaster();// 给子类扩展初始化其他BeanonRefresh();// 注册监听器registerListeners();/*** 设置转换器* 注册一个默认的属性值解析器* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean*/finishBeanFactoryInitialization(beanFactory);/*** 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,* spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka* 启动所有实现了Lifecycle接口的类* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了* ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人*/finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}destroyBeans();cancelRefresh(ex);throw ex;}finally {resetCommonCaches();}}
}

obtainFreshBeanFactory() 方法会解析所有 spring 配置文件。在此也证明了我们的推断:在 IOC 容器启动时,会去解析所有的 spring 配置文件

obtainFreshBeanFactory() 方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 1.刷新 BeanFactory,并执行加载和解析配置文件的操作refreshBeanFactory();// 2.拿到刷新后的 BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;
}
  • refreshBeanFactory():刷新 BeanFactory,并执行加载和解析配置文件的操作
  • getBeanFactory():拿到刷新后的 BeanFactory

refreshBeanFactory() 方法

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {...@Overrideprotected final void refreshBeanFactory() throws BeansException {// 判断是否存在beanFactoryif (hasBeanFactory()) {// 注销所有的单例 beandestroyBeans();// 重置beanFactorycloseBeanFactory();}try {// 创建一个新的BeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();// 指定序列化id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象beanFactory.setSerializationId(getId());// 定制BeanFactorycustomizeBeanFactory(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,那么就销毁单例 bean 以及关闭其 beanFactory
  • createBeanFactory():创建一个新的 BeanFactory,并指定序列化其 Id
  • customizeBeanFactory():定制自定义的 BeanFactory
  • loadBeanDefinitions():加载 bean 定义

destroyBeans() 方法(重点)

注意 destroyBeans() 方法:它只能销毁单例 bean,原因可以查看文章: spring 源码之 bean 的销毁

protected void destroyBeans() {getBeanFactory().destroySingletons();
}

继续看 destroySingletons() 方法

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {...@Overridepublic void destroySingletons() {// 调用父类的销毁方法销毁单例beansuper.destroySingletons();// 清空手工注册的beanName的缓存this.manualSingletonNames.clear();// 清空类型-->beanName的映射缓存clearByTypeCache();}
}

这里不再赘述 destroySingletons() 方法,详情可以查看:spring 源码之 bean 的销毁中的 destroySingletons() 方法

loadBeanDefinitions() 方法(重点)

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {...@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// 为指定beanFactory创建XmlBeanDefinitionReader(加载解析bean)XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// 对beanDefinitionReader进行环境变量的设置beanDefinitionReader.setEnvironment(getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// 对beanDefinitionReader进行设置,空方法initBeanDefinitionReader(beanDefinitionReader);// 设置loadBeanDefinitions的配置文件loadBeanDefinitions(beanDefinitionReader);}...
}

进入到 loadBeanDefinitions() 方法中

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {// 1.获取配置文件路径String[] configLocations = getConfigLocations();if (configLocations != null) {for (String configLocation : configLocations) {// 2.根据配置文件路径加载 bean 定义reader.loadBeanDefinitions(configLocation);}}
}// AbstractRefreshableWebApplicationContext.java
@Override
public String[] getConfigLocations() {return super.getConfigLocations();
}// AbstractRefreshableConfigApplicationContext.java
protected String[] getConfigLocations() {return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}// XmlWebApplicationContext.java
@Override
protected String[] getDefaultConfigLocations() {if (getNamespace() != null) {return new String[]{DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};} else {return new String[]{DEFAULT_CONFIG_LOCATION};}
}

经过调试 configLocations = [“classpath:applicationContext-spring.xml”] 如下


其中

public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

以上代码分析可知:如果不在 web.xml 中配置 contextConfigLocation 属性的话,spring 会读取 contextConfigLocation 的默认值 "/WEB-INF/applicationContext.xml"

<!-- web.xml 中配置 contextConfigLocation属性 -->
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-spring.xml</param-value>
</context-param>

reader.loadBeanDefinitions(configLocation) 方法

抽象类 AbstractBeanDefinitionReaderloadBeanDefinitions() 方法

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {// 获取 resourceLoader,这边为 XmlWebApplicationContextResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");}// 判断 resourceLoader 是否为 ResourcePatternResolver 的实例if (resourceLoader instanceof ResourcePatternResolver) {try {// 根据路径拿到该路径下所有符合的配置文件,并封装成ResourceResource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);// 根据Resource,加载Bean的定义int loadCount = loadBeanDefinitions(resources);if (actualResources != null) {for (Resource resource : resources) {actualResources.add(resource);}}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// 只能通过绝对URL加载单个资源Resource resource = resourceLoader.getResource(location);// 根据Resource,加载Bean的定义int loadCount = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;}
}

resources 调试如下

loadBeanDefinitions(resources) 方法

@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");int counter = 0;// 1.遍历所有的Resourcefor (Resource resource : resources) {// 2.根据Resource加载bean的定义,XmlBeanDefinitionReader实现counter += loadBeanDefinitions(resource);}return counter;
}

loadBeanDefinitions(resource) 方法

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {// 加载 bean 定义return loadBeanDefinitions(new EncodedResource(resource));
}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());}// 1.当前正在加载的EncodedResourceSet<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet<EncodedResource>(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}// 2.将当前encodedResource添加到currentResourcesif (!currentResources.add(encodedResource)) {// 如果添加失败,代表当前的encodedResource已经存在,则表示出现了循环加载throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}try {// 3.拿到Resource的inputStreamInputStream inputStream = encodedResource.getResource().getInputStream();try {// 4.将inputStream封装成org.xml.sax.InputSourceInputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 5.加载 bean 定义(方法以do开头,真正处理的方法)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();}}
}

doLoadBeanDefinitions() 方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 1.根据inputSource和resource加载XML文件,并封装成DocumentDocument doc = doLoadDocument(inputSource, resource);// 2.根据返回的Document注册Bean信息(对配置文件的解析,核心逻辑)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);}
}

registerBeanDefinitions() 方法(注册 bean 信息)

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {// 1.使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReaderBeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 2.记录统计前BeanDefinition的加载个数int countBefore = getRegistry().getBeanDefinitionCount();// 3.createReaderContext:根据resource创建一个XmlReaderContext// 4.registerBeanDefinitions:加载及注册Bean定义documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 5.返回本次加载的BeanDefinition个数return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入到 documentReader.registerBeanDefinitions(doc, createReaderContext(resource))

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");// 1.拿到文档的子节点,对于Spring的配置文件来说,理论上应该都是<beans>Element root = doc.getDocumentElement();// 2.通过拿到的节点,注册 Bean 定义doRegisterBeanDefinitions(root);
}

doRegisterBeanDefinitions() 方法

将从 spring 配置文件拿到的节点,注册 Bean 定义

protected void doRegisterBeanDefinitions(Element root) {BeanDefinitionParserDelegate parent = this.delegate;// 构建BeanDefinitionParserDelegatethis.delegate = createDelegate(getReaderContext(), root, parent);// 1.校验root节点的命名空间是否为默认的命名空间(默认命名空间http://www.springframework.org/schema/beans)if (this.delegate.isDefaultNamespace(root)) {// 2.处理profile属性String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);// 校验当前节点的 profile 是否符合当前环境定义的, 如果不是则直接跳过, 不解析该节点下的内容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;}}}// 3.解析前处理, 留给子类实现preProcessXml(root);// 4.解析并注册bean定义parseBeanDefinitions(root, this.delegate);// 5.解析后处理, 留给子类实现postProcessXml(root);this.delegate = parent;
}

parseBeanDefinitions() 方法

解析并注册 bean 定义,此方法就是解析 xml 配置文件的方法

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {// 1.默认命名空间的处理if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();// 遍历root的子节点列表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)) {// 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" />parseDefaultElement(ele, delegate);}else {// 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>delegate.parseCustomElement(ele);}}}} else {// 2.自定义命名空间的处理delegate.parseCustomElement(root);}
}
  • 来到了解析 bean 定义的核心部分,这边会遍历 root 节点(正常为 <beans> 节点)下的所有子节点,对子节点进行解析处理
  • 如果节点的命名空间是 spring 默认的命名空间,则走 parseDefaultElement(ele, delegate) 方法进行解析,例如最常见的:<bean>
  • 如果节点的命名空间不是 spring默认的命名空间,也就是自定义命名空间,则走 delegate.parseCustomElement(ele) 方法进行解析,例如常见的: <context:component-scan/>、<aop:aspectj-autoproxy/>
  • 默认的命名空间为:http://www.springframework.org/schema/beans,其他都是自定义命名空间,例如下图 aop 的命名空间为:http://www.springframework.org/schema/aop

parseDefaultElement(ele, delegate) 源码分析:https://blog.csdn.net/v123411739/article/details/86669952

parseCustomElement(ele) 源码分析:https://blog.csdn.net/v123411739/article/details/87447290

obtainFreshBeanFactory() 方法总结

  • 该方法会解析所有 spring 配置文件(通常我们会放在 resources 目录下),将所有 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory
  • 常见的,如果解析到 <context:component-scan base-package="" /> 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory

而所谓的加载到 BeanFactory 中的内容主要指的是添加到以下 3 个缓存

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
}public class SimpleAliasRegistry implements AliasRegistry {private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
}
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;int ROLE_APPLICATION = 0;int ROLE_SUPPORT = 1;int ROLE_INFRASTRUCTURE = 2;void setParentName(@Nullable String parentName);@NullableString getParentName();void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName();void setScope(@Nullable String scope);@NullableString getScope();void setLazyInit(boolean lazyInit);boolean isLazyInit();void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();void setAutowireCandidate(boolean autowireCandidate);boolean isAutowireCandidate();void setPrimary(boolean primary);boolean isPrimary();void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName();ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !getConstructorArgumentValues().isEmpty();}MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !getPropertyValues().isEmpty();}boolean isSingleton();boolean isPrototype();boolean isAbstract();int getRole();@NullableString getDescription();@NullableString getResourceDescription();@NullableBeanDefinition getOriginatingBeanDefinition();
}

obtainFreshBeanFactory() 方法流程总结

  • 如果已经有 beanFactory,那么关闭其 beanFactory;然后创建一个新的 BeanFactory:DefaultListableBeanFactory
  • 根据 web.xmlspring 默认的配置文件 contextConfigLocation 配置的路径,读取 spring 配置文件,验证配置文件的内容,并封装成 Resource
  • 根据 Resource 加载 XML 配置文件,并解析成 Document 对象
  • 拿到 Document 中的根节点,遍历根节点和所有子节点

参考:https://blog.csdn.net/v123411739/article/details/86563620

Spring源码之bean的解析obtainFreshBeanFactory方法解读相关推荐

  1. Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)

    五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 ,  指定初始化方法 init-method 方法​ 二 ,指定销毁 ...

  2. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  3. Spring源码之Bean的注册(使用XML配置的方式)

    本文分析的Spring源码是5.2.2版本,使用Gradle进行管理. 一.Bean的注册,先来看通过XML配置Bean的方式 1.配置applicationContext.xml: <?xml ...

  4. 一、如何阅读Spring源码(全网最简单的方法)

    学习Java最好最有效的方法是学习Spring,但是最笨最没效的方法也是学习Spring. 为什么这么说呢?道理其实很简单 A.Spring很庞大,很完善,也非常的底层,如果我们学会的Spring,那 ...

  5. Spring源码分析——Bean的生命周期

    文章目录 说明 测试代码 说明 本文从源码的角度分析Spring中Bean的加载过程,本文使用的Spring版本为4.3.25.RELEASE 测试代码 测试代码如下,根据这段简单的测试代码,一步步跟 ...

  6. 深入浅出Spring源码:IOC原理解析(一)

    IOC(Inversion of Control),即控制反转,意思是将对象的创建和依赖关系交给第三方容器处理,我们要用的时候告诉容器我们需要什么然后直接去拿就行了.举个例子,我们有一个工厂,它生产各 ...

  7. Spring源码之Bean的注册(注解方式)

    1.创建AnnotationConfigApplicationContext AnnotationConfigApplicationContext context = new AnnotationCo ...

  8. Spring源码学习--Bean的生命周期

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

  9. spring源码之bean加载(bean解析下篇)

    bean的加载步骤: MyTestBean bean = (MyTestBean) bf.getBean("myTestBean"); 步骤: (1) 转换对应的beanName ...

  10. Spring源码之启动过程(四)—— Bean的实例化详解

    前面,我们把Bean的生命周期做了一个概述和梳理,为的是更深刻的理解容器启动及Bean的生命周期,最主要的是Bean的实例化过程,没有看过的,可以进去先看一下(文章链接:Spring源码之Bean的生 ...

最新文章

  1. 中南财经政法大学计算机考研难吗,中南财经政法大学考研难吗(考研难度分析)...
  2. thymeleaf rs 查询结果_第十一章 JDBC与MySQL数据库(10)——通用查询
  3. 传统BI为什么注定会失败?
  4. webpack 配置详解
  5. LeetCode 67. 二进制求和
  6. 一层循环时间复杂度_算法的时间与空间复杂度(一看就懂)
  7. JavaScript中的高级特性及特别对象、属性和方法
  8. perl 判断不包含某字符串
  9. 对讲机怎么用_对讲机防水透气解决方案是怎么做的?
  10. 【渝粤教育】广东开放大学 知识产权法 形成性考核 (44)
  11. Niushop开源微信商城+小程序商城源码
  12. phpbb简体中文语言包的安装
  13. 如何生成一个APP_ID
  14. 游戏开发:目前主流游戏引擎的分析报告
  15. Navicat 的使用
  16. 2017ACM ICPC Asia Regional-Daejeon H-Rock Paper Scissors[ FFT]
  17. ifft java_在Matlab中的fft / ifft反卷积
  18. Qt编写高仿苹果MAC电脑输入法(支持触摸滑动选词)
  19. 番茄花园系统剖析 下
  20. HaaS100 云端钉一体智能语音播放器设计

热门文章

  1. 容器技术Docker K8s 46 Serverless Kubernetes(ASK)详解-场景应用
  2. 翻译:如何理解K-means的缺点
  3. 易筋SpringBoot 2.1 | 第十三篇:SpringBoot综合应用多个DataSoure
  4. 万兆网口和千兆网口区别_万兆网卡的安装以及注意事项
  5. 重载前自增运算符和后自增运算符
  6. python游戏程序中游戏对象是什么_Python游戏编程入门
  7. 来电通java版_Java 程序员常用的 11 款免费 IDE 编辑器
  8. MongoDB 在windows shell环境下的基本操作和命令的使用示例(二)
  9. 【CF 706】(C.Hard problem) + (D.Vasiliy's Multiset) + (E.Working routine)【最短路、01字典树、十字链表模拟】
  10. 实数域上的压缩映射不动点原理