​ 本文是针对Srping的ClassPathXMLApplicationContext来进行源码解析,在本篇博客中将不会讲述spring Xml解析注册代码,因为ApplicationContext是BeanFactory的扩展版本,ApplicationContext的GetBean和xml解析注册BeanDefinition都是用一套代码,如果您是第一次看请先看一下XMLBeanFactory解析和BeanFactory.GetBean源码解析:

作者整理了spring-framework 5.x的源码注释,代码已经上传者作者的GitHub了,可以让读者更好的理解,地址:

  • 接下来直接上源码:
package lantao;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.lantao.UserBean; public class ApplicationContextTest { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean.xml");
UserBean userBean = (UserBean) applicationContext.getBean("userBean");
System.out.println(userBean.getName());
} }

在这里直接使用ClassPathXmlApplicationContext进行xml解析,在这里xml解析的代码和GetBean的代码就不过多的描述了,ApplicationContext是BeanFactory的扩展,所以想要看这两部分源码的请看作者的上两篇博客Sprin源码解析;

  • 接下来我们看一下ClassPathXmlApplicationContext的源码:
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException { super(parent);
// 支持解析多文件
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

在setConfigLocations方法中将资源文件放入configLocations全局变量中,,并且支持多文件解析,接下来我们你看一下重点,refresh方法;

  • 源码refresh方法:
@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.
// 对beanFactory的各种功能填充,加载beanFactory,经过这个方法 applicationContext就有了BeanFactory的所有功能
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
// 对beanFactory进行各种功能填充
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
// 允许在context子类中对BeanFactory进行post-processing。
// 允许在上下文子类中对Bean工厂进行后处理
// 可以在这里进行 硬编码形式的 BeanFactoryPostProcessor 调用 addBeanFactoryPostProcessor
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
// 激活各种BeanFactory处理器 BeanFactoryPostProcessors是在实例化之前执行
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
// 注册 拦截Bean创建 的Bean处理器,这里只是注册,真正地调用在getBean的时候 BeanPostProcessors实在init方法前后执行 doCreateBean方法中的 实例化方法中执行
// BeanPostProcessor执行位置:doCreateBean --> initializeBean --> applyBeanPostProcessorsBeforeInitialization 和 applyBeanPostProcessorsAfterInitialization
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
//为上下文初始化Message源,(比如国际化处理) 这里没有过多深入
initMessageSource(); // Initialize event multicaster for this context.
//初始化应用消息广播,并放入 applicationEventMulticaster bean中
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
//留给子类来初始化其它的bean
onRefresh(); // Check for listener beans and register them.
//在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
//初始化剩下的单实例
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
//完成刷新过程,通知生命周期护处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人(LifecycleProcessor 用来与所有声明的bean的周期做状态更新)
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();
}
}
}

对于ApplicationContext来说,refresh方法几乎涵盖了所有的基础和扩展功能,接下来看一下这个方法都做了什么;

  1. 刷新上下文,初始化前的准备工作;
  2. 加载beanFactory,经过这个方法 applicationContext就有了BeanFactory的所有功能
  3. 对beanFactory进行各种功能填充
  4. 允许在这里对BeanFactory的二次加工,例如:可以在这里进行硬编码方法的对BeanFactory进行BeanFactoryPostProcessor或BeanPostProcessor的操作;在这里简单说一下BeanFactoryPostProcessor是在bean实例化之前执行的,BeanPostProcessor是在初始化方法前后执行的,BeanFactoryPostProcessor操作的是BeanFactoryBeanPostProcessor操作的是Bean,其次这里还涉及了一个扩展BeanDefinitionRegistryPostProcessor它是继承了BeanFactoryPostProcessor,并且还有自己的定义方法 postProcessBeanDefinitionRegistry,这个方法可以操作BeanDefinitionRegistry,BeanDefinitionRegistry有个最主要的方法就是registerBeanDefinition,可以注册BeanDefinition,可以用这方法来处理一下不受spring管理的一下bean;
  5. 处理所有的BeanFactoryPostProcessor,也可以说是激活BeanFactory处理器,在这个方法里会先处理BeanDefinitionRegistryPostProcessor,在处理BeanFactoryPostProcessor,因为BeanDefinitionRegistryPostProcessor有自己的定义,所以先执行;
  6. 注册BeanPostProcessors ,这里只是注册,真正地调用在getBean的时候 BeanPostProcessors是在init方法前后执行 BeanPostProcessor执行位置:doCreateBean --> initializeBean --> applyBeanPostProcessorsBeforeInitialization 和 applyBeanPostProcessorsAfterInitialization方法中;
  7. 为上下文初始化Message源,(比如国际化处理) 这里没有过多深入;
  8. 初始化应用消息广播,初始化 applicationEventMulticaster ,判断使用自定义的还是默认的;
  9. 留给子类来初始化其它的bean;
  10. 在所有注册的bean中查找 ApplicationListener bean,注册到消息广播器中;
  11. 初始化剩下的单实例(非懒加载),这里会是涉及conversionService,LoadTimeWeaverAware,冻结BeanFactory,初始化Bean等操作;
  12. 完成刷新过程,包括 清除 下文级资源(例如扫描的元数据),通知生命周期处理器lifecycleProcessor并strat,同时publish Event发出ContextRefreshEvent通知别人;
  • 先来看prepareRefresh方法:
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
// 标志,指示是否已关闭此上下文
this.closed.set(false);
// 指示此上下文当前是否处于活动状态的标志
this.active.set(true); if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
} // Initialize any placeholder property sources in the context environment.
// 对上下文环境中的任何属性源进行分类。
initPropertySources(); // Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties, //验证标示为必填的属性信息是否都有了 ConfigurablePropertyResolver#setRequiredProperties 方法
getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
} // Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

一眼望去,可能觉得这个方法没有做什么,其实这方法中除了Closed和Active,最重要的是initPropertySources和getEnvironment().validateRequiredProperties()方法;

  1. initPropertySources证符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需要重写initPropertySourece方法,并在方法中进行个性化的属性处理及设置。
  2. validateRequiredProperties则是对属性进行验证,那么如何验证呢?举个融合两句代码的小例子来理解。

例如现在有这样一个需求,工程在运行过程中用到的某个设置(例如VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,工程不会工作。这一要求也各种各样的解决办法,在Spring中可以这么做,可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext.当然,最好的办法是对源码进行扩展,可以自定义类:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String.. configLocations){
super(configLocations);
}
protected void initPropertySources(){
//添加验证要求
getEnvironment().setRequiredProterties("VAR");
}
}

自定义了继承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了个性化需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统并没有检测到对应VAR的环境变量,将抛出异常。当然我们还需要在使用的时候替换掉原有的ClassPathXmlApplicationContext:

public static void main(Stirng[] args){
ApplicationContext bf = new MyClassPathXmlApplicationContext("myTest.xml");
User user = (User)bf.getBean("testBean");
}

上述案例来源于:Spring源码深度解析(第二版)141页;

  • 接下来看一下obtainFreshBeanFactory方法,在这里初始化DefaultListAbleBeanFactory并解析xml:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}

点击并拖拽以移动

/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// createBeanFactory方法直接新建一个DefaultListableBeanFactory,内部使用的是DefaultListableBeanFactory实例
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化id
beanFactory.setSerializationId(getId());
// 定制beanFactory工厂
customizeBeanFactory(beanFactory);
// 加载BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
// 使用全局变量记录BeanFactory
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

点击并拖拽以移动

看一下上述方法都做了什么:

  1. 判断BeanFactory是否存在,如果存在则销毁所有Bean,然后关闭BeanFactory;

  2. 使用createBeanFactory方法直接新建一个DefaultListableBeanFactory,内部使用的是DefaultListableBeanFactory实例;

  3. 设置BeanFactory的设置序列化id

  4. 定制beanFactory工厂,也就是给allowBeanDefinitionOverriding(是否允许覆盖同名称的Bean)和allowCircularReferences(是否允许bean存在循环依赖),可通过setAllowBeanDefinitionOverriding和setAllowCircularReferences赋值,这里就可通过商编初始化方法中的initPropertySources方法来进行赋值;

  package lantao;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyApplicationContext extends ClassPathXmlApplicationContext { public MyApplicationContext(String... configLocations){
super(configLocations);
}
protected void initPropertySources(){
//添加验证要求
getEnvironment().setRequiredProperties("VAR"); // 在这里添加set
super.setAllowBeanDefinitionOverriding(true);
super.setAllowCircularReferences(true);
}
}
  1. 加载BeanDefinition,就是解析xml,循环解析,这里就不看了,如果不了解看作者上篇博客;
  • 下面看一下prepareBeanFactory方法源码:
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// 设置BeanFactory的classLoader为当前context的classloader
beanFactory.setBeanClassLoader(getClassLoader()); // Spel语言解析器
// 设置BeanFactory的表达式语言处理器 Spring3中增加了表达式语言的支持
// 默认可以使用#{bean.xxx}的形式来调用相关属性值
// 在Bean实例化的时候回调用 属性填充的方法(doCreateBean 方法中的 populateBean 方法中的 applyPropertyValues 方法中的 evaluateBeanDefinitionString ) 就会判断beanExpressionResolver是否为null操作
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 为BeanFactory增加一个默认的 PropertyEditor 这个主要对bean的属性等设置管理的一个工具 增加属性注册编辑器 例如:bean property 类型 date 则需要这里
// beanFactory会在初始化 BeanWrapper(initBeanWrapper)中调用 ResourceEditorRegistrar 的 registerCustomEditors 方法
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks.
// ApplicationContextAwareProcessor --> postProcessBeforeInitialization
// 注册 BeanPostProcessor BeanPostProcessor 实在实例化前后执行的
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 设置几个忽略自动装配的接口 在addBeanPostProcessor方法中已经对下面几个类做了处理,他们就不是普通的bean了,所以在这里spring做bean的依赖的时候忽略
// doCreateBean 方法中的 populateBean 方法中的 autowireByName 或 autowireByType 中的 unsatisfiedNonSimpleProperties 中的 !isExcludedFromDependencyCheck(pd) 判断,
// 在属性填充的时候回判断依赖,如果存在下属几个则不做处理 对于下面几个类可以做implements操作
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
// 设置几个注册依赖 参考spring源码深度解析原文:当注册依赖解析后,例如但那个注册了对BeanFactory。class的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory的类型变回将beanFactory 实例注入进去
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners.
// 寄存器早期处理器,用于检测作为ApplicationListener的内部bean。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found.
// 增加了对AxpectJ的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} // Register default environment beans.
// 添加默认的系统环境bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

不说废话,直接看这个方法都做了什么:

  1. 设置BeanFactory的classLoader为当前context的classloader;

  2. 设置BeanFactory的表达式语言处理器 Spring3中增加了Spel表达式语言的支持, 默认可以使用#{bean.xxx}的形式来调用相关属性值,

    在Bean实例化的时候回调用 属性填充的方法(doCreateBean 方法中的 populateBean 方法中的 applyPropertyValues 方法中的 evaluateBeanDefinitionString ) 就会判断beanExpressionResolver是否为null操作,如果不是则会使用Spel表达式规则解析

    <?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-3.0.xsd"> <bean id="testOneBean" class="lantao.bean.TestOneBean">
    <property name="testTwoBean" value="#{testTWoBean}"/>
    </bean> <bean id="testTWoBean" class="lantao.bean.TestTwoBean"/> <!-- 上面 相当于 下边 --> <bean id="testOneBean1" class="lantao.bean.TestOneBean">
    <property name="testTwoBean" ref="testTWoBean1"/>
    </bean> <bean id="testTWoBean1" class="lantao.bean.TestTwoBean"/> </beans>
    1. 为BeanFactory增加一个默认的 PropertyEditor 这个主要对bean的属性等设置管理的一个工具 增加属性注册编辑器 例如:User类中 startDate 类型 date 但是xml property的value是2019-10-10,在启动的时候就会报错,类型转换不成功,这里可以使用继承PropertyEditorSupport这个类机型重写并注入即可使用;beanFactory会在初始化BeanWrapper (initBeanWrapper)中调用 ResourceEditorRegistrar 的 registerCustomEditors 方法进行初始化;
  3. 配置BeanPostProcessor,这里配置的是ApplicationContextAwareProcessor,上边我们说了,BeanPostProcessor是在初始化方法Init前后执行,看一下ApplicationContextAwareProcessor的Before和After方法:

@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null; // 该方法也会在 BeanFactory 实例化bean 中调用 doCreateBean --> initializeBean --> applyBeanPostProcessorsBeforeInitialization --> postProcessBeforeInitialization
// 如果实例化的类实现了 invokeAwareInterfaces 方法中的判断类 则会调用初始方法赋值
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}

在Before方法中调用了invokeAwareInterfaces方法,在invokeAwareInterfaces方法中做了类型 instanceof 的判断,意思就是如果这个Bean实现了上述的Aware,则会初始会一下资源,比如实现了ApplicationContextAware,就会setApplicationContext,这里相信大家都用过,就不多说了;

  1. 设置几个忽略自动装配的接口 在addBeanPostProcessor方法中已经对下面几个类做了处理,他们就不是普通的bean了,所以在这里spring做bean的依赖的时候忽略,在doCreateBean 方法中的 populateBean 方法中的 autowireByName 或 autowireByType 中的 unsatisfiedNonSimpleProperties 中的 !isExcludedFromDependencyCheck(pd) 判断,如果存在则不做依赖注入了;

  2. 设置几个注册依赖 参考spring源码深度解析原文:当注册依赖解析后,例如当注册了对BeanFactory的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory的类型便会将beanFactory 实例注入进去;

  3. 添加BeanPostProcessor,这里是添加ApplicationListener,是寄存器早期处理器;这里可以看作者的源码测试,在spring-context的test测试类下有;

  4. 增加了对AxpectJ的支持

  5. 注册默认的系统环境bean,environment ,systemProperties,systemEnvironment;

  • 上述就是对BeanFactory的功能填充,下面看postProcessBeanFactory:

postProcessBeanFactory方法是个空方法,允许在上下文子类中对Bean工厂进行后处理,例如:可以在这里进行 硬编码形式的 BeanFactoryPostProcessor 调用 addBeanFactoryPostProcessor,进行addBeanFactoryPostProcessor或者是BeanPostProcessor;

  • 接下来看一下invokeBeanFactoryPostProcessors方法:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>(); // 对 BeanDefinitionRegistry 类型处理
if (beanFactory instanceof BeanDefinitionRegistry) {
// 强转
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; // 普通的处理器
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); //注册处理器
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); // 这里就是硬编码处理 因为这里是从 getBeanFactoryPostProcessors()方法获取的 可以硬编码从addBeanFactoryPostProcessor()方法添加
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { // 对于 BeanDefinitionRegistryPostProcessor 类型 在 BeanFactoryPostProcessor 的基础上还有自己的定义,需要先调用
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; // 执行 继承 BeanDefinitionRegistryPostProcessor 类的 postProcessBeanDefinitionRegistry 方法
registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
//上边的For循环只是调用了硬编码的 BeanDefinitionRegistryPostProcessor 中的 postProcessBeanDefinitionRegistry 方法,
// 但是 BeanFactoryPostProcessor 中的 postProcessBeanFactory 方法还没有调用,是在方法的最后一行
// invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); 这两个方法中执行的, // 下面是自动处理器 获取类型是BeanDefinitionRegistryPostProcessor beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); 获取的 // 当前注册处理器
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先调用实现了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor类的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 下一个 ,调用实现 Ordered 的 BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor类的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后,调用所有其他BeanDefinitionRegistryPostProcessors,直到不再显示其他BeanDefinitionRegistryPostProcessors 无序的
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor类的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
} // 现在,调用到目前为止处理的所有处理器的 执行BeanFactoryPostProcessor 类的 postProcessBeanFactory 方法
// 这里执行的是 硬编码 和 非硬编码(自动)的 BeanFactoryPostProcessor 类的 postProcessBeanFactory 方法 分为硬编码处理器 和 普通处理器
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// 调用在上下文实例中注册的工厂处理器的postProcessBeanFactory方法。 就是硬编码 通过 addBeanFactoryPostProcessor 方法添加的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
} // 自动处理 非硬编码 获取类型为是BeanFactoryPostProcessor beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest. // 实现 priorityOrdered 的
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); // 实现 Ordered 的
List<String> orderedPostProcessorNames = new ArrayList<>(); // 无序的
List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}

上述代码看起来很多,但是总计起来就三件事:

  1. 执行硬编码的和主动注入的BeanDefinitionRegistryPostProcessor,调用postProcessBeanDefinitionRegistry方法;
  2. 执行硬编码的和主动注入的BeanFactoryPostProcessor,调用postProcessBeanFactory方法;
  3. 自动注入的可继承Ordered排序,priorityOrdered排序或无序;

上述测试在作者的spring源码congtext中lantao包下有测试用例;

  • registerBeanPostProcessors方法源码:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 使用 priorityOrdered保证顺序
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); // MergedBeanDefinitionPostProcessor
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); // 使用order保证顺序
List<String> orderedPostProcessorNames = new ArrayList<>(); // 无序的
List<String> nonOrderedPostProcessorNames = new ArrayList<>(); // 进行add操作
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // First, register the BeanPostProcessors that implement PriorityOrdered.
// 首先 注册实现PriorityOrdered的 BeanPostProcessors 先排序PostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered.
// 下一个,注册实现Ordered的BeanPostProcessors
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors.
// 现在,注册所有常规注册。无序的
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors.
// 最后,注册所有MergedBeanDefinitionPostProcessor类型的BeanPostProcessor,并非重复注册。
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 添加 ApplicationListener探测器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

registerBeanPostProcessors方法代码还是比较长的,它和invokeBeanFactoryPostProcessors方法最主要的区别就是registerBeanPostProcessors只在这里注册,但不在这里调用,做的事情和invokeBeanFactoryPostProcessors差不多:

  1. 使用priorityOrdered,Ordered或无序保证顺序;
  2. 通过beanFactory.addBeanPostProcessor(postProcessor)进行注册;

很简单,代码篇幅很长,但是很好理解,这里可以简单看一下;

  • 接下来是initMessageSource方法,这里作者没有过多的看源码,后续补上吧.......(抱歉)

  • initApplicationEventMulticaster源码:

/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 使用自定义的 广播
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 使用spring 默认的广播
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}

initApplicationEventMulticaster方法中主要就是判断是使用自定义的ApplicationEventMulticaster(广播器)还是使用呢Spring默认的SimpleApplicationEventMulticaster广播器;

  • onRefresh 方法是留个子类重写的,内容是空;

  • registerListeners方法:

/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
// 注册 添加 ApplicationListener 这里通过硬编码 addApplicationListener 方法添加的
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
} // Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 注册 添加 ApplicationListener 这里是自动注册添加的
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} // Publish early application events now that we finally have a multicaster...
// 发布早期的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

registerListeners方法做了三件事情:

  1. 添加 ApplicationListener 这里通过硬编码 addApplicationListener 方法添加的;
  2. 添加 ApplicationListener 是通过自动注册添加的
  3. 发布早起事件
  • finishBeanFactoryInitialization方法源码:
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// conversionService 用于类型转换 ,比如 String 转Date
//判断BeanFactory中是否存在名称为“conversionService”且类型为ConversionService的Bean,如果存在则将其注入到beanFactory
// 判断有无自定义属性转换服务接口,并将其初始化,我们在分析bean的属性填充过程中,曾经用到过该服务接口。在TypeConverterDelegate类的convertIfNecessary方法中
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
} // Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
} // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 得到所有的实现了LoadTimeWeaverAware接口的子类名称,初始化它们
// 如果有LoadTimeWeaverAware类型的bean则初始化,用来加载Spring Bean时织入第三方模块,如AspectJ,我们在后面详细讲解。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
} // Stop using the temporary ClassLoader for type matching.
// 停止使用临时类加载器 就是在这里不让使用呢 ClassLoader 了
beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes.
// 冻结所有bean定义,说明你注册的bean将不被修改或进行任何进一步的处理 就是不让改了 BeanDefinition
beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有非懒加载的 单例 bean 调用你getBean方法
beanFactory.preInstantiateSingletons();
}

finishBeanFactoryInitialization方法做了五件事情:

  1. 设置BeanFactory的conversionService,conversionService用于类型转换使用, 例如:User类中 startDate 类型 date 但是xml property的value是2019-10-10,在启动的时候就会报错,类型转换不成功,可以使用conversionService;书中170页有具体代码;
  2. 添加BeanFactory的addEmbeddedValueResolver,读取配置信息放到这里,可以通过EmbeddedValueResolverAware来获取,参考:https://www.cnblogs.com/winkey4986/p/7001173.html
  3. 得到所有的实现了LoadTimeWeaverAware接口的子类名称,初始化它们,用来加载Spring Bean时织入第三方模块,如AspectJ,我们在后面详细讲解。
  4. 停止使用临时类加载器 就是在这里不让使用呢 ClassLoader 了
  5. 冻结所有bean定义,说明你注册的bean将不被修改或进行任何进一步的处理 就是不让改了 BeanDefinition
  6. 初始化所有非懒加载的 单例 bean 调用你getBean方法,循环所有bean并实例化 条件是:单例,非Abstract 非懒加载
  • 最后的一个方法finishRefresh:
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除 下文级资源(例如扫描的元数据)。
clearResourceCaches(); // Initialize lifecycle processor for this context.
// 在当前context中初始化 lifecycle
// lifecycle 有自己的 start/ stop方法,实现此接口后spring保证在启动的时候调用start方法开始生命周期 关闭的时候调用 stop方法结束生命周期
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
// onRefresh 启动所有实现了 lifecycle 的方法
getLifecycleProcessor().onRefresh(); // Publish the final event.
// 当ApplicationContext初始化完成发布后发布事件 处理后续事宜
publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
// 这里 没明白》。。
LiveBeansView.registerApplicationContext(this);
}

finishRefresh方法是ApplicationContext初始化的最后一个方法了,他做了一些结尾的事情:

  1. 清除 下文级资源(例如扫描的元数据)。
  2. 在当前context中初始化 lifecycle,lifecycle 有自己的 start/ stop方法,实现此接口后spring保证在启动的时候调用start方法开始生命周期 关闭的时候调用 stop方法结束生命周期。
  3. onRefresh 启动所有实现了 lifecycle 的方法,调用了start方法。
  4. 当ApplicationContext初始化完成发布事件 处理后续事宜。
  5. LiveBeansView.registerApplicationContext(this)这个代码没有太明白,有大神可以留言;

至此ApplicationContext的源码就都已经分析完成了,其中有很多地方很难懂,大家可以对应着源码一起看,会好理解一些,如果其中有错误,欢迎大神指点,在下方留言。

Spring源码之ApplicationContext的更多相关文章

  1. Spring源码阅读-ApplicationContext体系结构分析

    目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...

  2. spring源码:ApplicationContext的增强功能(li)

    ApplicationContext作为资源加载器:ApplicationContext作为事件发布者: Java原生提供了事件发布机制------EventObject对象作为发布的事件,Event ...

  3. spring源码解析-ApplicationContext解析

    ApplicationContext和BeanFactory一样都是bean的容器,而BeanFactory是一切Bean容器的父类,ApplicationContext继承于BeanFactory( ...

  4. 【Spring 源码】ApplicationContext源码

    ApplicationConetxt体系

  5. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  6. 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现

    传送门 可以加载XML两种方法 使用 BeanFactory 加载 XML BeanFactory bf = new XmlBeanFactory(new ClassPathResource(&quo ...

  7. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  8. spring源码:web容器启动(li)

    web项目中可以集成spring的ApplicationContext进行bean的管理,这样使用起来bean更加便捷,能够利用到很多spring的特性.我们比较常用的web容器有jetty,tomc ...

  9. Spring源码分析——资源访问利器Resource之实现类分析

    今天来分析Spring的资源接口Resource的各个实现类.关于它的接口和抽象类,参见上一篇博文——Spring源码分析——资源访问利器Resource之接口和抽象类分析 一.文件系统资源 File ...

随机推荐

  1. 最新 Apple iPhone 12 价格 All In One

    最新 Apple iPhone 12 价格 All In One 美版价格 Apple iPhone 12 mini $699 Apple iPhone 12 $799 Apple iPhone 12 ...

  2. React & Strict Mode

    React & Strict Mode https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects ...

  3. how to get window width in javascript

    how to get window width in javascript how to get window width in js How to Detect Screen Resolution ...

  4. svg & stroke & style & class

    svg & stroke & style & class svg selected style methods style class, !important fill, st ...

  5. NGK又双叒叕送钱了!百万SPC空投不要错过!

    不知不觉,2021年已然到来.回顾过去一年,2020年币圈发生的事情真的是太多太多,比特币的持续暴涨,DeFi一波又一波的空投福利,都让我们见识了区块链的魅力!同样,2021年区块链市场的牛市仍然持续 ...

  6. 【从零开始撸一个App】Fragment和导航中的使用

    Fragment简介 Fragment自从Android 3.0引入开始,它所承担的角色就是显而易见的.它之于Activity就如html片段之于页面,好处无需赘述. Fragment的生命周期和Ac ...

  7. keepalived-1.3.5+MHA部署mysql集群

    MHA: MHA工作原理总结为以下几条: 从宕机崩溃的master保存二进制日志事件(binlog events): 识别含有最新更新的slave: 应用差异的中继日志(relay log)到其他sl ...

  8. 用一次就会爱上的cli工具开发

    本文转载自用一次就会爱上的cli工具开发 写在前面 最近接手任务--使用nodejs开发一个公司内部使用的cli工具,简而言之就是输入一行命令快速搭建好项目结构,也可以通过不同的命令引入不同的文件. ...

  9. Nifi组件脚本开发—ExecuteScript 使用指南(二)

    Part 2 - FlowFile I/O 和 Error Handling flow File的IO NiFi 的 Flow files 由两个主要部件组成:attributes 和 content ...

  10. 用OkHttpGo和FastJson获取OneNET云平台数据(解析嵌套数组)

    JSON数据格式有两种,一种是 { } 大括号表示的JSON对象,一种是 [ ] 中括号表示的JSON数组.从OneNET获取到的数组是这样的,并用Json解析网址查看https://jsonform ...