深入浅出spring原理及实战「源码调试分析」结合datasourceregister深入分析importbeandefinitionregistrar的源码运作流程

author author     2023-01-17     491

关键词:

每日一句

人的一生中不可能会一帆风顺,总会遇到一些挫折,当你对生活失去了信心的时候,仔细的看一看、好好回想一下你所遇到的最美好的事情吧,那会让你感觉到生活的美好


注入案例代码

如何通过实现SpringBoot框架带有的ImportBeanDefinitionRegistrar注册器,注入我们想要注册的bean对象实例。只需要采用@Import的注解进行注入对应的一类相关的bean对象。

@Import(DataSourceRegister.class,A.class)
@SpringBootApplication
@ComponentScan("com.libo")
public class LiboApplication
public static void main(String[] args)
SpringApplication sa = new SpringApplication(LiboApplication.class);
sa.run(args);

DataSourceRegister的开发实现

  • 在springboot启动的时候,loader模块会根据“清单文件”加载该Application类,并反射调用psvm入口函数main,@Import注解也可以导入一个常规类,并且创建注入很多对象实例
  • DataSourceRegister类是用来进行初始化数据源和并提供了执行动态切换数据源的工具类。

DataSourceRegister注入主数据源和从数据源

这里DataSourceRegister继承的EnvironmentAware接口,没有真正意义上去用它的用途,本身可以通过这个setEnvironment方法,进行注入Environment对象,从而可以读取其他的配置信息,目前主要用作一个hook方法。

读取对应的环境变量
public final void setEnvironment(Environment environment) 
DruidEntity druidEntity = FileUtil.
readYmlByClassPath("db_info", DruidEntity.class);
defaultTargetDataSource =
DataSourceUtil.createMainDataSource(druidEntity);

主要用于读取Druid的数据源模型信息。进行创建对应的数据源对象defaultTargetDataSource

注入Bean到Spring容器中

registerBeanDefinitions注册BeanDefinition对象模型

public final void registerBeanDefinitions(AnnotationMetadata  annotationMetadata, BeanDefinitionRegistry  beanDefinitionRegistry) 
// 0.将主数据源添加到数据源集合中
DataSourceSet.putTargetDataSourcesMap(MAINDATASOURCE,defaultTargetDataSource);
//1.创建DataSourceBean
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
//spring名称约定为defaultTargetDataSource和targetDataSources
mpv.addPropertyValue("defaultTargetDataSource",defaultTargetDataSource);
mpv.addPropertyValue("targetDataSources",DataSourceSet.getTargetDataSourcesMap());
beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
完整的DataSourceRegister的案例
public class DataSourceRegister<T> implements EnvironmentAware, ImportBeanDefinitionRegistrar 

private javax.sql.DataSource defaultTargetDataSource;

static final String MAINDATASOURCE = "mainDataSource";

public final void setEnvironment(Environment environment)
DruidEntity druidEntity = FileUtil.
readYmlByClassPath("db_info", DruidEntity.class);
defaultTargetDataSource =
DataSourceUtil.createMainDataSource(druidEntity);


public final void registerBeanDefinitions(AnnotationMetadata
annotationMetadata, BeanDefinitionRegistry
beanDefinitionRegistry)
// 0.将主数据源添加到数据源集合中
DataSourceSet.putTargetDataSourcesMap(MAINDATASOURCE,
defaultTargetDataSource);
//1.创建DataSourceBean
GenericBeanDefinition beanDefinition = new
GenericBeanDefinition();
beanDefinition.setBeanClass(DataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
//spring名称约定为defaultTargetDataSource和targetDataSources
mpv.addPropertyValue("defaultTargetDataSource",
defaultTargetDataSource);
mpv.addPropertyValue("targetDataSources",
DataSourceSet.getTargetDataSourcesMap());
beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);

执行流程解读
  • 动态数据源注册器类实现了ImportBeanDefinitionRegistrar接口,没错就是这个原因,由于实现了该接口让该类成为了拥有注册bean的能力。
  • 原理上也能说得通作为一个Bean的注册类是没有必要被注册为Spring容器的Bean对象
  • 虽然这样解释也不为过但我仍然想一探究竟,本来想大概找找spring涉及关键类如:ConfigurationClass,ConfigurationClassParser等,接下来我们需要看一下SpringBoot的总体加载流程。

SpringApplication类的run方法

SpringBoot启动时使用了SpringApplication类的run方法来牵引整个spring的初始化过程,源码如下。

public ConfigurableApplicationContext run(String... args) 
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
// 错误原因分析器
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
// 重点分析:启动所有的运行的监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
try
// 解析ApplicationArgument数据
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 通过监听器和传递的参数,实现相关的配置环境对象信息,预先
// 进行配置Environment对象,设置全局环境变量容器
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
// 输出相关的Banner控制,根据配置以及相关的Environment
Banner printedBanner = this.printBanner(environment);
// 创建Spring容器上下文。
context = this.createApplicationContext();
//创建和赋值错误解析器
analyzers = new FailureAnalyzers(context);
// 准备环境上下文进行配置相关的容器的上下文的参数。
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文容器
this.refreshContext(context);
// 后置执行上下文操作
this.afterRefresh(context, applicationArguments);
// 完成监听器的后置完成处理操作
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if(this.logStartupInfo)
(new StartupInfoLogger(this.mainApplicationClass)).
logStarted(this.getApplicationLog(), stopWatch);

return context;
catch (Throwable var9)
this.handleRunFailure(context, listeners,
(FailureAnalyzers)analyzers,
var9);
throw new IllegalStateException(var9);

根据上面的源码流程可以分析重点的加载过程

  1. 重点分析:启动所有的运行的监听器,获取SpringApplicationRunListeners; 从类路径下META-INF/spring.factories。回调所有的获取SpringApplicationRunListener.starting() 方法。
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
  1. 解析ApplicationArgument数据以及封装命令行参数,通过program参数的部分进行解析,并且加载到PropertiesSourcePlaceHolder中的环境变量容器内部。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

通过上面的监听器和传递的参数,实现相关的配置环境对象信息,预先进行配置Environment对象,设置全局环境变量容器

  1. 根据上面的全局变量容器进行配置以及初始化相关的Environment对象。
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
  1. 创建Spring容器上下文,在createApplicationContext当中,由于我们是web项目,则spring默认给我们创建了一个
context = this.createApplicationContext();

【深入浅出Spring原理及实战】「源码调试分析」结合DataSourceRegister深入分析ImportBeanDefinitionRegistrar的源码运作流程_初始化

AnnotationConfigEmbeddedWebApplicationContext,当然它也是继承GenericWebApplicationContext类和GenericApplicationContext类的,那么他默认会持有一个DefaultListableBeanFactory对象,这个对象可以用来创建Bean。

  1. 准备环境上下文进行配置相关的容器的上下文的参数
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  1. 刷新上下文容器,refreshContext就是在做spring运行后的初始化工作。
this.refreshContext(context);

接着往下走,进入refreshContext中会调用一系列的refresh方法,最终进入AbstractApplicationContext中,主要将SpringBoot的容器对象数据和原本基础的Spring Framework的框架对象进行加载到容器中。

@Override
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 Springs core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();


invokeBeanFactoryPostProcessors() 方法就是Bean在注册前期做的一系列数据收集工作,BeanDefinitionRegistry的容器注册BeanDefinition之前,调用相关的

跟着堆栈继续深入,会进入到这个方法中,这个方法就是初始化bean前的所有轨迹:

【深入浅出Spring原理及实战】「源码调试分析」结合DataSourceRegister深入分析ImportBeanDefinitionRegistrar的源码运作流程_数据源_02

在invokeBeanFactoryPostProcessors方法中继续跟进一系列方法就会看到在一开始的时候spring会初始化几个系统固有的Bean

【深入浅出Spring原理及实战】「源码调试分析」结合DataSourceRegister深入分析ImportBeanDefinitionRegistrar的源码运作流程_数据源_03

继续调试后的关键点出现在这个方法中:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) 
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames)
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef))
if (logger.isDebugEnabled())
logger.debug("Bean definition has already been processed
as a configuration class: " + beanDef);


else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory))
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));


// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty())
return;

// Sort by previously determined @Order value, if applicable
Collections.sort(configCandidates, new
Comparator<BeanDefinitionHolder>()
@Override
public int compare(BeanDefinitionHolder bd1,
BeanDefinitionHolder bd2)
int i1 =
ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 =
ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;

);
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry)
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet && sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR))
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;


// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
do
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null)
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());

this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length)
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<String>();
for (ConfigurationClass configurationClass : alreadyParsed)
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());

for (String candidateName : newCandidateNames)
if (!oldCandidateNames.contains(candidateName))
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName()))
candidates.add(new BeanDefinitionHolder(bd, candidateName));



candidateNames = newCandidateNames;


while (!candidates.isEmpty());

// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null)
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME))
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());



if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory)
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();

而通过不断重复调试确定获得注册Bean的列表应该发生在配置的“剖析阶段”,也就是parser.parse(candidates);这个方法的内部,到了这里基本问题的答案已经要浮出水面了,我也不再粘贴无用的代码,如果你真的对这个问题比骄傲好奇可以自己跟踪并练习调试的源码技巧!

当然在ConfigurationClassParser这个类中parse方法也是不少,只要静下心来逐渐分析,马上就能准确的找到Override的parse方法。

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException 
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION))
return;


ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null)
if (configClass.isImported())
if (existingClass.isImported())
existingClass.mergeImportedBy(configClass);

// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;

else
// Explicit bean definition found, probably replacing an import.
// Lets remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();)
if (configClass.equals(it.next()))
it.remove();





// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do
sourceClass = doProcessConfigurationClass(configClass, sourceClass);//处理定义的配置类

while (sourceClass != null);

this.configurationClasses.put(configClass, configClass);
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException

// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);

// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class))
if (this.environment instanceof ConfigurableEnvironment)
processPropertySource(propertySource);

else
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");



// Process any @ComponentScan annotations Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN))
for (AnnotationAttributes componentScan : componentScans)
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions)
if (ConfigurationClassUtils.checkConfigurationClassCandidate(
holder.getBeanDefinition(), this.metadataReaderFactory))
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());





// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);//处理注解导入的类型

// Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName()))
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources)
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);



// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));


// Process default methods on interfaces
processInterfaces(configClass, sourceClass);

// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass())
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass))
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();



// No superclass -> processing is complete
return null;

以上两个方法中标红的就是关键点。而且spring的大师们也把注释写的十分明显:”//Process any @Import annotations“,到这里已经彻底豁然开朗!

spring会先去处理scan,将你程序内部的所有要注册的Bean全部获得(自然包括那些configuration),这里统称为ConfigurationClass,scan全部整理完毕后才会去处理@Import注解时导入的类!

我们回到最初的问题 DataSourceRegister和A两个类为什么A成为了Bean但DataSourceRegister却未成为Bean呢?

在processImports方法中,很明显candidate.isAssignable(ImportBeanDefinitionRegistrar.class)时操作为:configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());而普通的类通过processConfigurationClass(candidate.asConfigClass(configClass));方法,最终会被放在ConfigurationClassParser类的成员变量configurationClasses中,最终被初始化为Bean。

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException

if (importCandidates.isEmpty())
return;


if (checkForCircularImports && isChainedImportOnStack(configClass))
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));

else
this.importStack.push(configClass);
try
for (SourceClass candidate : importCandidates)
if (candidate.isAssignable(ImportSelector.class))
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector)
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));

else
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);


else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class))
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

else
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));



catch (BeanDefinitionStoreException ex)
throw ex;

catch (Throwable ex)
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);

finally
this.importStack.pop();


后置执行上下文操作

this.afterRefresh(context, applicationArguments);

完成监听器的后置完成处理操作

listeners.finished(context, (Throwable)null);

至此,总体的mportBeanDefinitionRegistrar的对象注入体系就基本介绍完了

深入浅出spring原理及实战「源码原理实战」从底层角度去分析研究propertysourcesplaceholderconfigurer的原理及实战注入机制

Spring提供配置解析功能主要有一下xml文件占位符解析和Java的属性@Value的占位符解析配置这两种场景进行分析和实现解析,如下面两种案例。xml文件的占位符解析配置<beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"init-method="i... 查看详情

深入浅出spring原理及实战「原理分析专题」不看源码就带你剖析ioc容器核心流程以及运作原理

这是史上最全面的Spring的核心流程以及运作原理的分析指南🍃【Spring核心专题】「IOC容器篇」不看繁琐的源码就带你浏览Spring的核心流程以及运作原理🍃【Spring核心专题】「AOP容器篇」不看繁琐的源码就带你浏览Spring的... 查看详情

深入浅出spring原理及实战「原理分析专题」不看源码就带你剖析mvc容器核心流程以及运作原理

前提回顾之前已经写了很多问斩针对于SpringMVC的的执行原理和核心流程,在此再进行冗余介绍就没有任何意义了,所以我们主要考虑的就是针对于SpringMVC还没但大框架有介绍的相关内容解析分析和说明,那么接下来就... 查看详情

深入浅出spring原理及实战「原理分析专题」从零开始教你springel表达式使用和功能分析讲解指南(上篇)(代码片段)

SpringEL表达式语言,这种语言jsp中学到的el,但是在整个spring之中其表达式语言要更加的复杂,而且支持度更加的广泛,最重要的是他可以进行方法的调用,对象的实例化,集合操作等等,但是唯一的难点就是:代码太复杂了,表达式太复杂... 查看详情

深入浅出spring原理及实战「原理分析专题」不看源码就带你剖析aop容器核心流程以及运作原理(代码片段)

前提回顾前一篇文章主要介绍了spring核心特性机制的IOC容器机制和核心运作原理,接下来我们去介绍另外一个较为核心的功能,那就是AOP容器机制,主要负责承接前一篇代理模式机制中动态代理:JDKProxy和CglibProxy... 查看详情

精华推荐|深入浅出rocketmq原理及实战「底层源码挖掘系列」透彻剖析贯穿rocketmq的消费者端的运行核心的流程(上篇)

精华推荐|【深入浅出RocketMQ原理及实战】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行核心的流程上篇:分析对应总体消费流程的判断和校验以及限流控制和回调等处理流程分析下篇:分析基于上篇的总体流程的... 查看详情

深入浅出spring原理及实战「开发实战系列」spring-cache扩展自定义(注解失效时间+主动刷新缓存)(代码片段)

缓存失效时间支持在方法的注解上指定SpringCache默认是不支持在@Cacheable上添加过期时间的,可以在配置缓存容器时统一指定:@BeanpublicCacheManagercacheManager(@SuppressWarnings("rawtypes")RedisTemplateredisTemplate)Custo 查看详情

深入浅出sentinel原理及实战「基础实战专题」零基础探索分析sentinel控制台开发指南

Sentinel控制台Sentinel提供了一个轻量级的开源控制台SentinelDashboard,它提供了机器发现与健康情况管理、监控(单机和集群)、规则管理与推送等多种功能。Sentinel控制台提供的功能如下查看机器列表以及健康情况:Sentnel控制台能... 查看详情

深入浅出springcloud原理及实战「springcloud-alibaba系列」微服务模式搭建系统基础架构实战指南及版本规划踩坑分析

前提介绍SpringCloud-Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过SpringCloud编程模型轻松使用这些组件来开发分布式应用服务。依托SpringCloudAlibaba,您只需要... 查看详情

深入浅出springcloud原理及实战「netflix系列之hystrix」针对于限流熔断组件hystrix的基本参数和实现原理介绍分析(代码片段)

...此度过糟糕的一生。[温馨提示]承接第一篇文章🏹【深入浅出SpringCloud原理及实战】「Netflix系列之Hystrix」针对于限流熔断组件Hystrix的基本参数和实现原理介绍分析在这里推荐给大家martinfowler的熔断器介绍和权威指南,有兴趣... 查看详情

深入浅出springcloud原理及实战「netflix系列之hystrix」针对于限流熔断组件hystrix的超时机制的原理和实现分析(代码片段)

...此度过糟糕的一生。[温馨提示]承接第一篇文章🏹【深入浅出SpringCloud原理及实战】「Netflix系列之Hystrix」针对于限流熔断组件Hystrix的基本参数和实现原理介绍分析在这里推荐给大家martinfowler的熔断器介绍和权威指南,有兴趣... 查看详情

深入浅出rocketmq原理及实战「底层原理挖掘系列」透彻剖析贯穿rocketmq的消息发送的全部流程和落盘原理分析指南(代码片段)

前言介绍RocketMQ目前在国内应该是比较流行的MQ了,目前本人也在公司的项目中进行使用和研究,借着这个机会,分析一下RocketMQ发送一条消息到存储一条消息的过程,这样会对以后大家分析和研究RocketMQ相关的问... 查看详情

深入浅出spring原理及实战「开发实战系列」重新回顾一下异常重试框架springretry的功能指南和实战(代码片段)

重试机制的业务背景外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要用失败重试策略重新调用API接口来获取。在分布式系统中... 查看详情

深入浅出springcloud原理及实战「网关服务体系」微服务网关服务的gateway组件的原理介绍分析

为什么要有服务网关?我们都知道在微服务架构中,系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?难道要一个个的去调用吗?很显然这是不太实际的,我们需要有一个统一的接口... 查看详情

spring事务管理transactionproxyfactorybean源码分析

J2EE,当然离不开事务,事务又当然少不了Spring声明式事务。spring声明式事务,很多码农门,应该和笔者一样,停留在使用上,及仅仅了解点原理。如:Spring事务管理原理“代理+AOP”,再深入了解就不太清楚了。一直对声明式事务... 查看详情

精华推荐|深入浅出rocketmq原理及实战「底层原理挖掘系列」透彻剖析贯穿rocketmq的broker服务端自动创建topic的原理分析和问题要点指南

前提背景使用RocketMQ进行发消息时,一般我们是必须要指定topic,此外topic必须要提前建立,但是topic的创建(自动或者手动方式)的设置有一个开关autoCreateTopicEnable,此部分主要会在broker节点的配置文件的时候进行设置,运行环... 查看详情

阅读书单2020

...精通MongoDB实战(第二版)应用密码学协议、算法与C源程序深入浅出密码学——常用加密技术原理与应用机器学习深入理解Java虚拟机:JVM高级特性与最佳实践HotSpot实战深入浅出promethuseElasticSearch源码解析与优化实践Tensorflow:... 查看详情

深入浅出springcloud原理及实战「netflix系列之hystrix」针对于限流熔断组件hystrix的command创建和执行实现原理分析(代码片段)

创建流程构建HystrixCommand或者HystrixObservableCommand对象使用Hystrix的第一步是创建一个HystrixCommand或者HystrixObservableCommand对象来表示你需要发给依赖服务的请求。若只期望依赖服务每次返回单一的回应,按如下方式构造一个HystrixC... 查看详情