原创文章,转发请标注https://www.cnblogs.com/boycelee/p/12595884.html

分析例子

启动类

Application,使用的是ClassPathXmlApplicationContext来加载xml文件

/**
* @author jianw.li
* @date 2020/3/16 11:53 PM
* @Description: TODO
*/
public class MyApplication {
private static final String CONFIG_LOCATION = "classpath:application_context.xml"; private static final String BEAN_NAME = "hello"; public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(CONFIG_LOCATION);
Hello hello = (Hello) ac.getBean(BEAN_NAME);
hello.sayHello();
}
}

Bean

/**
* @author jianw.li
* @date 2020/3/16 11:53 PM
* @Description: TODO
*/
public class Hello { public void sayHello() {
System.out.println("Hello World");
}
}

配置文件

​ 在resources下建立名为classpath:application_context.xml的配置文件,并配置好Bean

<?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="hello" class="com.boyce.bean.Hello"></bean> </beans>

总体结构

ClassPathXmlApplicationContext继承体系如下:

IoC总体结构图如下:

源码分析

BeanFactory获取

ClassPathXmlApplicationContext

//构造函数,创建ClassPathXmlApplicationContext,其中configLocation为Bean所在的文件路径
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
} public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//null
super(parent);
//设置配置路径至ApplicationContext中
setConfigLocations(configLocations);
if (refresh) {
//核心方法,refresh会将旧的ApplicaionContext销毁
refresh();
}
}

AbstractApplicationContext

refresh

​ 核心方法,refresh销毁旧ApplicationContext,生成新的ApplicationContext

@Override
public void refresh() throws BeansException, IllegalStateException {
//加锁.没有明确对象,只是想让一段代码同步,可以创建Object startupShutdownMonitor = new Object()
synchronized (this.startupShutdownMonitor) {
// 为context刷新准备.设置启动时间,设置激活状态等
prepareRefresh(); // 告知子类刷新内部bean factory.
// 获取BeanFactory,默认实现DefaultListableBeanFactory
// 加载BeanDefinition,并注册至BeanDefinitionRegistry
// (核心)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
// 进行BeanFactory的预准备工作,对BeanFactory进行信息设置
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
// BeanFactory准备工作
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
// 实例化实现BeanFactoryPostProcessor接口的Bean,并调用接口方法
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
// 注册BeanPostProcessors(Bean的后置处理器),创建Bean的前后等执行
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
// 初始化MessageSource组件,国际化相关功能
initMessageSource(); // Initialize event multicaster for this context.
// 初始化事件派发器
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
// 子类重写,在容器刷新时可以自定义逻辑;如创建Tomcat、Jetty等Web服务器
onRefresh(); // Check for listener beans and register them.
// 注册应用的监听器(注册实现ApplicationListener接口的监听器bean)
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有非懒加载单例bean
// 属性填充
// 初始化方法的调用(例如afterPropertiesSet、init-method方法)
// 调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
// (核心)
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();
}
}
}
obtainFreshBeanFactory

​ 告知子类刷新内部bean factory.

​ 核心方法,初始化BeanFactory、加载Bean、注册Bean

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新Bean工厂,关闭并销毁旧BeanFacroty
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory

​ 关闭并销毁旧BeanFactory,创建与初始化新BeanFactory。为什么是DefaultListableBeanFactory?

@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已有BeanFactory
if (hasBeanFactory()) {
// 如果已有,则销毁beans且关闭BeanFactory
destroyBeans();
closeBeanFactory();
}
try {
//初始化DefaultListableBeanFactory,为什么选择实例化DefaultListableBeanFactory?而不是其他的Bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
//Bean工厂序列化设置id
beanFactory.setSerializationId(getId());
//定制Bean工厂,设置不允许覆盖Bean,不允许循环依赖等
customizeBeanFactory(beanFactory);
//加载BeanDefinitions
loadBeanDefinitions(beanFactory);
//此处synchronized块与#hasBeanFactory中的synchronized块存在关联,此处锁住之后hasBeanFactory中的synchronized块将等待
//避免beanFactory未销毁或未关闭的情况
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
customizeBeanFactory

​ 定制BeanFactory。设置Bean覆盖、循环依赖等。什么是循环依赖?

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
//默认值为false不允许对Bean进行覆盖
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
//默认值为false,不允许循环依赖
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}

BeanFactory获取时序图

BeanDefinition加载注册

AbstractXmlApplicationContext

loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 为BeanFactory创建XmlBeanDefinitionReader对象,用于解析xml对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
// 为beanDefinitionReader设置环境信息
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);
//加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
//加载资源对象,最终还是会回到这种方式去加载bean.
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//加载资源路径吗
reader.loadBeanDefinitions(configLocations);
}
}

AbstractBeanDefinitionReader

loadBeanDefinitions
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
//循环配置文件路径
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
} if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
// 将xml转为Resource,所以上面的两种资源加载方式,最终都会回到Resource为参数的加载方式
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 加载资源配置中的BeanDeinition对象,并返回数量
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 {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
// 就算是入参为location的loadBeanDefinitions,最终也会回到入参为resource的loadBeanDefinitions中
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
counter += loadBeanDefinitions(resource);
}
return counter;
}

XmlBeanDefinitionReader

loadBeanDefinitions

​ 从详细的XML文件中加载Bean

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());
} //用于存储编译过的Reource
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 {
// 将xml文件流封装为InputSource对象
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 执行加载BeanDefinitions
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

​ 从xml文件中加载bean,将xml转为Document并注册Bean

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将xml转为Document
Document doc = doLoadDocument(inputSource, resource);
// 解析document对象,封装BeanDefinition对象并注册Bean
return registerBeanDefinitions(doc, resource);
}
...
}
registerBeanDefinitions

​ 计算从当前配置文件中加载bean的数量

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取已注册的BeanDefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 计算新注册BeanDefinition的数量并返回
return getRegistry().getBeanDefinitionCount() - countBefore;
}

DefaultBeanDefinitionDocumentReader

registerBeanDefinitions

​ 从“spring-beans” xsd中解析bean。什么是xsd?XML结构定义 ( XML Schemas Definition)

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
// 执行注册BeanDefinitions
doRegisterBeanDefinitions(root);
}
doRegisterBeanDefinitions

​ 从根节点开始注册每一个Bean

/**
* Register each bean definition within the given root {@code <beans/>} element.
* 从根节点开始注册每一个Bean
*/
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.
//可以通过spring.profiles.active设定当前环境激活的profile,例如配置prod,可以通过@ActiveProfiles配置 // 解析bean定义
// 委托模式
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) {
//获取元素中profile属性,可以通过xml或@Profile设置当前bean所属的profile
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
//不能做profile属性则直接跳过
if (StringUtils.hasText(profileSpec)) {
//配置多profile
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
//元素中的profile是否是环境指定的profiles之一
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
//不在当前环境指定的profile中则return
return;
}
}
} preProcessXml(root);
// 解析元素
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); this.delegate = parent;
}
parseBeanDefinitions

​ 从文档根节点开始解析元素,import、alias、bean等

/**
* 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)) {
//解析default namespace下的元素(例如:<import>、<alias>、<beans>、<bean>)
parseDefaultElement(ele, delegate);
}
else {
//解析Custom元素(例如:<mvc>、<context>、<aop>),自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
parseDefaultElement

​ 解析default namespace下的元素(例如:、、、)

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)) {
//解析bean元素为BeanDefinition
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
processBeanDefinition

​ 获取bean元素解析并注册

/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
* 获取bean元素解析并注册
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean元素成BeanDefinition,并将BeanDefinition封装成BeanDefinitionHolder对象
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//注册装饰的实例,完成BeanDefinition注册
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));
}

BeanDefinitionReaderUtils

registerBeanDefinition
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 alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

DefaultListableBeanFactory

registerBeanDefinition
@Override
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);
}
} BeanDefinition oldBeanDefinition;
//beanDefinitionMap放置所有注册的Bean
oldBeanDefinition = this.beanDefinitionMap.get(beanName); //如果bean名已存在
if (oldBeanDefinition != null) {
//不允许覆盖bean
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
//通过比较BeanRole.判断谁覆盖谁
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
//新bean覆盖旧bean
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
//将bean放置beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//beanName没有与beanDefinitionMap中的重复
else {
//非正常情况下,其他的Bean已经初始化,如果已经有bean初始化,则使用者已经在进行业务操作,无法保证对beanDefinitionMap、beanDefinitionNames、manualSingletonNames进行操作的一些列动作的线程安全,所以需要加锁。参考:https://blog.csdn.net/qq_41907991/article/details/97614337
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
//bean放置beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
//记录bean名称
this.beanDefinitionNames.add(beanName);
//bean不需要手动注册
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
} if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

BeanDefinition加载注册流程图

总结

​ 至此已经完成了IoC容器的初始化。将xml文件中的bean元素解析为Bean,将Bean注册至注册中心,并发送注册事件。DefaultListableBeanFactory建立Bean配置信息,这些信息都存放在BeanDefinitionMap中,由IoC容器来维护。

​ 最后,懂得不多,做得很少。文章肯定又不少错误,如大家发现麻烦及时指出,为了避免误导更多人,我也会及时学习并修改!

引用参考

[1]《Spring技术内幕》

[2]https://www.javadoop.com/post/spring-ioc

[3]https://github.com/seaswalker/spring-analysis/blob/master/note/Spring.md#classpathxmlapplicationcontext

SpringFramework之IoC容器初始化的更多相关文章

  1. 【spring源码分析】IOC容器初始化(一)

    前言:spring主要就是对bean进行管理,因此IOC容器的初始化过程非常重要,搞清楚其原理不管在实际生产或面试过程中都十分的有用.在[spring源码分析]准备工作中已经搭建好spring的环境, ...

  2. 【spring源码分析】IOC容器初始化(三)

    前言:在[spring源码分析]IOC容器初始化(二)中已经得到了XML配置文件的Document实例,下面分析bean的注册过程. XmlBeanDefinitionReader#registerB ...

  3. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  4. 【Spring源码解析】—— 结合SpringMVC过程理解IOC容器初始化

    关于IOC容器的初始化,结合之前SpringMVC的demo,对其过程进行一个相对详细的梳理,主要分为几个部分: 一.IOC的初始化过程,结合代码和debug过程重点说明 1. 为什么要debug? ...

  5. 【spring源码分析】IOC容器初始化——查漏补缺(一)

    前言:在[spring源码分析]IOC容器初始化(十一)中提到了初始化bean的三个步骤: 激活Aware方法. 后置处理器应用(before/after). 激活自定义的init方法. 这里我们就来 ...

  6. 整理在Spring IOC容器初始化后可以处理特定逻辑的多种实现方式

    Spring框架的核心是依赖注入.切面:Spring Boot是在Spring框架的基础上为其提供许多默认配置.默认约定(约定优于配置),从而达到减少或减化配置进而可开箱即用.快速上手:Spring ...

  7. Spring IoC容器初始化过程学习

    IoC容器是什么?IoC文英全称Inversion of Control,即控制反转,我么可以这么理解IoC容器: 把某些业务对象的的控制权交给一个平台或者框架来同一管理,这个同一管理的平台可以称为I ...

  8. spring源码学习之路---深度分析IOC容器初始化过程(四)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 最近由于工作和生活,学习耽搁 ...

  9. spring源码 — 一、IoC容器初始化

    IoC容器初始化 注意:本次的spring源码是基于3.1.1.release版本 容器:具有获取Bean功能--这是最基本功能,也是BeanFactory接口定义的主要行为,在添加了对于资源的支持之 ...

随机推荐

  1. Hi3518_SDK

    第一章 Hi3518_SDK_Vx.x.x.x版本升级操作说明 如果您是首次安装本SDK,请直接参看第2章. 第二章 首次安装SDK 1.Hi3518 SDK包位置 在"Hi3518_V10 ...

  2. Leetcode 943. Find the Shortest Superstring(DP)

    题目来源:https://leetcode.com/problems/find-the-shortest-superstring/description/ 标记难度:Hard 提交次数:3/4 代码效 ...

  3. Spring源码分析-BeanFactoryPostProcessors 应用之 PropertyPlaceholderConfigurer

    BeanFactoryPostProcessors 介绍 BeanFactoryPostProcessors完整定义: /** * Allows for custom modification of ...

  4. Implementing 5G NR Features in FPGA

    目录 论文来源 论文简介 基本原理 论文创新点 借鉴之处 论文来源 2018 European Conference on Networks and Communications (EuCNC),Ja ...

  5. java集合-set

    #java集合-set Map用于存储key-value的映射,其中key的值是不能重复的.并且还需要正确的覆写equals方法和hashCode方法 如果我们只需要存储不重复的key,并不需要存储对 ...

  6. Ubutun18.04安装Python3.7.6

    最近因为环境问题,简单记录下Python3.7的安装过程: 下载地址:http://python.org/ftp/python/3.7.6/Python-3.7.6.tgz 编译安装步骤: sudo ...

  7. 网站提权之MSF骚操作

    当我们在进行web渗透测试的时候,拿到了webshell,但是在执行net user.whoami.类似的命令会发现怎么好像用不了,没有回显,权限不够,这可怎么办呐? 测试环境: 内网,没钱买服务器, ...

  8. .ArrayList是如何实现的,ArrayList和LinkedList的区别?ArrayList如何实现扩容?

    ArrayList比较简单,主要是通过数组来实现的 需要注意的是其初始容量是10 /** * Default initial capacity. */ private static final int ...

  9. 基于python openOPC的监控页面一

    笔者涉猎的工业领域项目遇到一个需求,需要把底层设备(表记)的状态和运行数据集中放到一个监控画面进行展示,数据需要在界面端实时进行刷新,类似网友的例子,如下图(侵删) 数据需要实时主动刷新,笔者基于多年 ...

  10. 基础JavaScript练习(一)总结

    任务目的 在上一任务基础上继续JavaScript的体验 接触一下JavaScript中的高级选择器 学习JavaScript中的数组对象遍历.读写.排序等操作 学习简单的字符串处理操作 任务描述 参 ...