SOFABoot源码解析之启动原理(2)-源码解析

异步初始化bean 前两天在看 SOFABoot 的时候,看到一个让我眼前一亮的东西,来给大家盘一下。SOFABoot,你可能不眼熟,但是没关系,本文也不是给你讲这个东西的,你就认为它是 SpringBoot 的变种就行了。因为有蚂蚁金服背书,所以主要是一些金融类的公司在使用这个框架:官方介绍是这样的:SOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等能力。 阅读详情

        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc作为SOFABoot应用(其实也是SpringBoot应用)启动源码分析的案例。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        在该案例中,采用WEB环境下使用的Spring应用上下文环境org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext。

        在SofaBootRpcDemoApplication的main方法中,调用SpringApplication的静态方法(S   ofaBootRpcDemoApplication.class, args),启动应用: 

1.  publicstatic ConfigurableApplicationContext run(Object[] sources, String[] args) {
2.       return new SpringApplication(sources).run(args);
3.  }

一、  创建SpringApplication实例

        在run方法中,首先创建SpringApplication实例: 

1.  publicSpringApplication(Object... sources) {
2.       initialize(sources);
3.  }

        在SpringApplication构造函数中,调用initialize方法进行SpringApplication实例初始化工作: 

1.  privatevoid initialize(Object[] sources) {
2.       if(sources != null && sources.length > 0) {
3.           this.sources.addAll(Arrays.asList(sources));
4.       }
5.       this.webEnvironment= deduceWebEnvironment();
6.       setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
8.       setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
9.       this.mainApplicationClass= deduceMainApplicationClass();
10. }

        在SpringApplication实例初始化的时候,主要做以下几件事情:

        1.   根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型;

        2.   使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer;

        3.   使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener;

        4.   推断并设置main方法的定义类;

二、  启动SOFABoot应用

        SpringApplication实例初始化完成后,开始执行run方法,启动SOFABoot应用。 

1.  public ConfigurableApplicationContextrun(String... args) {
2.       StopWatchstopWatch = new StopWatch();
3.       stopWatch.start();
4.       ConfigurableApplicationContextcontext = null;
5.       FailureAnalyzersanalyzers = null;
6.       configureHeadlessProperty();
7.       SpringApplicationRunListenerslisteners = getRunListeners(args);
8.       listeners.started();
9.       try{
10.          ApplicationArgumentsapplicationArguments = new DefaultApplicationArguments(args);
12.          ConfigurableEnvironmentenvironment = prepareEnvironment(listeners,
13.                  applicationArguments);
14.          BannerprintedBanner = printBanner(environment);
15.          context = createApplicationContext();
16.          analyzers= new FailureAnalyzers(context);
17.          prepareContext(context, environment,listeners, applicationArguments,
18.                  printedBanner);
19.          refreshContext(context);
20.          afterRefresh(context,applicationArguments);
21.          listeners.finished(context,null);
22.          stopWatch.stop();
23.          if(this.logStartupInfo) {
24.              newStartupInfoLogger(this.mainApplicationClass)
25.                      .logStarted(getApplicationLog(),stopWatch);
26.          }
27.          returncontext;
28.      }
29.      catch(Throwable ex) {
30.          handleRunFailure(context,listeners, analyzers, ex);
31.          throw new IllegalStateException(ex);
32.      }
33. }

        启动SOFABoot应用的主要工作就是创建和刷新Spring应用上下文。此处采用AnnotationConfigEmbeddedWebApplicationContext作为Spring应用上下文的实现类。

        启动SOFABoot应用的主要步骤如下:

        (一)    创建StopWatch实例,并启动,记录任务的运行时间;

        (二)    设置系统属性java.awt.headless;

        (三)    通过SpringFactoriesLoader类loadFactoryNames方法,查找并加载所有spring.factories文件中定义的SpringApplicationRunListener接口的实现,并调用started方法启动监听器;

      (四)   创建Spring应用上下文AnnotationConfigEmbeddedWebApplicationContext:      
1.  protectedConfigurableApplicationContext createApplicationContext() {
2.       Class<?>contextClass = this.applicationContextClass;
3.       if(contextClass == null) {
4.           try{
5.               contextClass =Class.forName(this.webEnvironment
6.                       ?DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
7.           }
8.           catch(ClassNotFoundException ex) {
9.               thrownew IllegalStateException(……略);
10.          }
11.      }
12.      return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);
13. }

        此处是WEB环境,所以创建AnnotationConfigEmbeddedWebApplicationContext实例: 

1.  publicAnnotationConfigEmbeddedWebApplicationContext() {
2.       this.reader = new AnnotatedBeanDefinitionReader(this);
3.       this.scanner= new ClassPathBeanDefinitionScanner(this);
4.  }

        在AnnotationConfigEmbeddedWebApplicationContext构造函数中,创建AnnotatedBeanDefinitionReader实例,用来处理含有注解的类。创建ClassPathBeanDefinitionScanner实例,用来扫描指定路径下含有注解的类。由于SOFAbBoot主要采用JavaConfig的配置形式,所以此处主要看一下AnnotatedBeanDefinitionReader实例化过程,以了解注解相关处理器的注册过程: 

1.    publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environmentenvironment) {
2.            ……略       
3.           AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
4.  }

    在Spring应用上下文中注册所有注解相关的Post Processors: 

1.  public staticSet<BeanDefinitionHolder> registerAnnotationConfigProcessors(
2.           BeanDefinitionRegistryregistry, Object source) {
3.   
4.       DefaultListableBeanFactorybeanFactory = unwrapDefaultListableBeanFactory(registry);
5.       ……略   
6.       Set<BeanDefinitionHolder>beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
7.       if(!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)){
8.           RootBeanDefinitiondef = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
9.           def.setSource(source);
10.          beanDefs.add(registerPostProcessor(registry,def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
11.      }
12.  
13.      if(!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
14.          RootBeanDefinitiondef = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
15.          def.setSource(source);
16.          beanDefs.add(registerPostProcessor(registry,def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
17.      }
18.  
19.      if(!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
20.          RootBeanDefinitiondef = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
21.          def.setSource(source);
22.          beanDefs.add(registerPostProcessor(registry,def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
23.      }
24.  
25.      //Check for JSR-250 support, and if present add theCommonAnnotationBeanPostProcessor.
26.      if(jsr250Present &&!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
27.          RootBeanDefinitiondef = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
28.          def.setSource(source);
29.          beanDefs.add(registerPostProcessor(registry,def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
30.      }
31.      ……略   
32.      if(!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
33.          RootBeanDefinition def = newRootBeanDefinition(EventListenerMethodProcessor.class);
34.          def.setSource(source);
35.          beanDefs.add(registerPostProcessor(registry,def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
36.      }
37.      if(!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
38.          RootBeanDefinitiondef = new RootBeanDefinition(DefaultEventListenerFactory.class);
39.          def.setSource(source);
40.          beanDefs.add(registerPostProcessor(registry,def, EVENT_LISTENER_FACTORY_BEAN_NAME));
41.      }
42.  
43.      returnbeanDefs;
44. }

        与注解相关的PostProcessors主要包括ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,EventListenerMethodProcessor,PersistenceAnnotationBeanPostProcessor,DefaultEventListenerFactory。

        其中,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口。当刷新Spring上下文(调用AbstractApplicationContext类refresh方法)过程中,调用AbstractApplicationContext类invokeBeanFactoryPostProcessors方法时,被调用执行。ConfigurationClassPostProcessor解析@Configuration注解,调用ConfigurationClassParser类的parse方法,处理@ComponentScan、@Import、@ImportResource、@Bean注解。

        AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor实现了BeanPostProcessor接口,在创建Bean实例时被调用。例如:在刷新Spring上下文(调用AbstractApplicationContext类refresh方法)过程中,调用finishBeanFactoryInitialization方法时,在实例化所有单例Bean对象时被调用。

        EventListenerMethodProcessor,DefaultEventListenerFactory是事件监听器相关的PostProcessors。

        至此,创建AnnotationConfigEmbeddedWebApplicationContext实例的主要步骤完成。

         (五)   准备Spring应用上下文:      
1.  private voidprepareContext(ConfigurableApplicationContext context,
2.           ConfigurableEnvironmentenvironment, SpringApplicationRunListeners listeners,
3.           ApplicationArgumentsapplicationArguments, Banner printedBanner) {
4.       context.setEnvironment(environment);
5.       postProcessApplicationContext(context);
6.       applyInitializers(context);
7.       listeners.contextPrepared(context);
8.       if(this.logStartupInfo) {
9.           logStartupInfo(context.getParent()== null);
10.          logStartupProfileInfo(context);
11.      }
12.  
13.      //Add boot specific singleton beans
14.      context.getBeanFactory().registerSingleton("springApplicationArguments",
15.              applicationArguments);
16.      if(printedBanner != null) {
17.          context.getBeanFactory().registerSingleton("springBootBanner",printedBanner);
18.      }
19.  
20.      //Load the sources
21.      Set<Object>sources = getSources();
22.      Assert.notEmpty(sources,"Sources must not be empty");
23.      load(context, sources.toArray(newObject[sources.size()]));
24.      listeners.contextLoaded(context);
25. }

        1.   设置Spring应用上下文Enviroment;

        2.   设置Spring应用上下文属性,如beanNameGenerator、resourceLoader等;

        3.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的ApplicationContextInitializer接口的实现的initialize方法,完成Spring应用上下文的初始化工作; 

        4.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的contextPrepared方法。该方法在Spring应用上下文创建完,并且前期准备工作完成,但加载资源以前,完成Spring应用上下文的一些处理工作;

        5.   创建BeanDefinitionLoader实例(构造函数中依次创建AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner),然后调用该实例的load方法注册run方法中参数指定的source资源(此处为SofaBootRpcDemoApplication)到Spring应用上下文,这个资源是ConfigurationClassPostProcessor类处理的入口配置类,可以是一个或多个;

        6.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的contextLoaded方法。该方法在Spring应用上下文已经被加载,但还没有刷新之前,完成Spring应用上下文的一些处理工作。

        (六)   刷新Spring应用上下文:
1.  public void refresh() throws BeansException,IllegalStateException {
2.       synchronized(this.startupShutdownMonitor) {
3.           //Prepare this context for refreshing.
4.           prepareRefresh();
5.   
6.           //Tell the subclass to refresh the internal bean factory.
7.           ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory();
8.   
9.           //Prepare the bean factory for use in this context.
10.          prepareBeanFactory(beanFactory);
11.  
12.          try{
13.              //Allows post-processing of the bean factory in context subclasses.
14.              postProcessBeanFactory(beanFactory);
15.  
16.              //Invoke factory processors registered as beans in the context.
17.              invokeBeanFactoryPostProcessors(beanFactory);
18.  
19.              //Register bean processors that intercept bean creation.
20.              registerBeanPostProcessors(beanFactory);
21.  
22.              //Initialize message source for this context.
23.              initMessageSource();
24.  
25.              //Initialize event multicaster for this context.
26.              initApplicationEventMulticaster();
27.  
28.              //Initialize other special beans in specific context subclasses.
29.              onRefresh();
30.  
31.              //Check for listener beans and register them.
32.              registerListeners();
33.  
34.              //Instantiate all remaining (non-lazy-init) singletons.
35.              finishBeanFactoryInitialization(beanFactory);
36.  
37.              //Last step: publish corresponding event.
38.              finishRefresh();
39.          }
40.  
41.          catch(BeansException ex) {
42.              if(logger.isWarnEnabled()) {
43.                  logger.warn("Exceptionencountered during context initialization - " +
44.                          "cancellingrefresh attempt: " + ex);
45.              }
46.  
47.              //Destroy already created singletons to avoid dangling resources.
48.              destroyBeans();
49.  
50.              //Reset 'active' flag.
51.              cancelRefresh(ex);
52.  
53.              //Propagate exception to caller.
54.              throwex;
55.          }
56.  
57.          finally{
58.              //Reset common introspection caches in Spring's core, since we
59.              //might not ever need metadata for singleton beans anymore...
60.              resetCommonCaches();
61.          }
62.      }
63. }

     看到这段代码,Spring开发人员都应该比较熟悉了。这段代码为Spring应用上下文的具体实现类调用父类AbstractApplicationContext的refresh方法进行刷新操作。对于整个Spring应用上下文刷新过程,大家应该都比较熟悉了,在此不详述了。

         此时,我们主要关注invokeBeanFactoryPostProcessors(beanFactory)方法:
1.  protected voidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2.       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors());
3.   
4.       ……略
5.  }

      该方法通过PostProcessorRegistrationDelegate调用所有实现BeanFactoryPostProcessor接口的实现类,完成beanFactory的一些处理工作。

1.  public static voidinvokeBeanFactoryPostProcessors(
2.           ConfigurableListableBeanFactorybeanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
3.   
4.       ……略
5.   
6.           //First, invoke the BeanDefinitionRegistryPostProcessors that implementPriorityOrdered.
7.          ……略
8.           invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors,registry);
9.   
10.          //Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
11.          ……略
12.          invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors,registry);
13.  
14.          //Finally, invoke all other BeanDefinitionRegistryPostProcessors until no furtherones appear.
15.          ……略
16.  
17.          //Now, invoke the postProcessBeanFactory callback of all processors handled sofar.
18.          invokeBeanFactoryPostProcessors(registryPostProcessors,beanFactory);
19.          invokeBeanFactoryPostProcessors(regularPostProcessors,beanFactory);
20.      }
21.  
22.      else{
23.          //Invoke factory processors registered with the context instance.
24.          invokeBeanFactoryPostProcessors(beanFactoryPostProcessors,beanFactory);
25.     }
26.  
27.      ……略
28.      //Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
29.      //Ordered, and the rest.
30.      ……略
31.      //First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
32.      ……略
33.      invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors,beanFactory);
34.  
35.      //Next, invoke the BeanFactoryPostProcessors that implement Ordered.
36.      ……略
37.      invokeBeanFactoryPostProcessors(orderedPostProcessors,beanFactory);
38.  
39.      //Finally, invoke all other BeanFactoryPostProcessors.
40.      ……略
41.      invokeBeanFactoryPostProcessors(nonOrderedPostProcessors,beanFactory);
42.  
43.      ……略
44. }
        在invokeBeanDefinitionRegistryPostProcessors方法中,调用实现了PriorityOrdered接口和BeanDefinitionRegistryPostProcessor接口的BeanFactoryPostProcessor的实现类ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法:
1.  public voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
2.      
3.        RootBeanDefinition iabpp = newRootBeanDefinition(ImportAwareBeanPostProcessor.class);
4.       iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
5.       registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME,iabpp);
6.   
7.       RootBeanDefinitionecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
8.       ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
9.       registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME,ecbpp);
10.        ……略
11.  
12.      processConfigBeanDefinitions(registry);
13. }

   在Spring应用上下文中注册BeanPostProcessor接口的实现类ImportAwareBeanPostProcessor、EnhancedConfigurationBeanPostProcessor;

        调用processConfigBeanDefinitions方法,开始处理@Configuration配置类。

        注意 ,此处是整个应用中所有@Configuration配置类的处理入口。在整个@Configuration配置类处理过程中,循环处理所有@Configuration配置类,直至所有@Configuration配置类处理完。        
1.  public void processConfigBeanDefinitions(BeanDefinitionRegistryregistry) {
2.       List<BeanDefinitionHolder>configCandidates = new ArrayList<BeanDefinitionHolder>();
3.       String[]candidateNames = registry.getBeanDefinitionNames();
4.   
5.       for(String beanName : candidateNames) {
6.           BeanDefinitionbeanDef = registry.getBeanDefinition(beanName);
7.           if(ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
8.                   ConfigurationClassUtils.isLiteConfigurationClass(beanDef)){
9.               ……略
10.          }
11.          elseif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {
12.              configCandidates.add(newBeanDefinitionHolder(beanDef, beanName));
13.          }
14.      }
15.       ……略
16.       ConfigurationClassParser parser = new ConfigurationClassParser(
17.              this.metadataReaderFactory,this.problemReporter, this.environment,
18.              this.resourceLoader,this.componentScanBeanNameGenerator, registry);
19.       ……略
20.      do {
21.          parser.parse(candidates);
22.          parser.validate();
23.  
24.          ……略
25.            // Read the model and create beandefinitions based on its content
26.          if(this.reader == null) {
27.              this.reader= new ConfigurationClassBeanDefinitionReader(
28.                      registry,this.sourceExtractor, this.resourceLoader, this.environment,
29.                      this.importBeanNameGenerator,parser.getImportRegistry());
30.          }
31.          this.reader.loadBeanDefinitions(configClasses);
32.          alreadyParsed.addAll(configClasses);
33.  
34.          candidates.clear();
35.          ……略
36.            for (ConfigurationClassconfigurationClass : alreadyParsed) {
37.                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
38.              }
39.              for(String candidateName : newCandidateNames) {
40.                  if(!oldCandidateNames.contains(candidateName)) {
41.                      BeanDefinitionbeanDef = registry.getBeanDefinition(candidateName);
42.                      if(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory) &&
43.                              !alreadyParsedClasses.contains(beanDef.getBeanClassName())){
44.                          candidates.add(newBeanDefinitionHolder(beanDef, candidateName));
45.                      }
46.                  }
47.              }       
48.      }
49.      while (!candidates.isEmpty());
50.  
51.      ……略
52. }

        @Configuration配置类主要处理步骤:

        1.   依次遍历DefaultListableBeanFactory中所有BeanDefinition,查找带有@Configuration注解的BeanDefinition,放入configCandidates。然后根据@order进行排序,此时只有一个包含@Configuration注解的类,即SofaBootRpcDemoApplication;

        2.   构造@Configuration注解的解析类ConfigurationClassParser;

        3.   依次遍历集合candidates中所有@Configuration配置类,逐一处理配置类中的注解,此时只有SofaBootRpcDemoApplication。
1.  public voidparse(Set<BeanDefinitionHolder> configCandidates) {
2.      
3.        this.deferredImportSelectors = newLinkedList<DeferredImportSelectorHolder>();
4.   
5.       for (BeanDefinitionHolder holder :configCandidates) {
6.           BeanDefinitionbd = holder.getBeanDefinition();
7.           try{
8.               if(bd instanceof AnnotatedBeanDefinition) {
9.                   parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
10.              }
11.              elseif (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
12.                  parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
13.              }
14.              else{
15.                  parse(bd.getBeanClassName(),holder.getBeanName());
16.              }
17.          }
18.          catch(BeanDefinitionStoreException ex) {
19.              throwex;
20.          }
21.          catch(Throwable ex) {
22.              thrownew BeanDefinitionStoreException(……略);
23.          }
24.      }
25.      processDeferredImportSelectors();
26. }

          依次处理每个@Configuration配置类,具体处理操作在doProcessConfigurationClass方法中实现,由于该方法负责具体处理每个@Configuration配置类,稍后在后面具体介绍。

        处理完传入的@Configuration配置类以后,处理实现DeferredImportSelector接口的ImportSelector类,主要用于有条件的加载某些类,如使用@Conditional注解。
1.  private voidprocessDeferredImportSelectors() {
2.       List<DeferredImportSelectorHolder>deferredImports = this.deferredImportSelectors;
3.       ……略
4.       for(DeferredImportSelectorHolder deferredImport : deferredImports) {
5.           ConfigurationClassconfigClass = deferredImport.getConfigurationClass();
6.           try{
7.               String[] imports =deferredImport.getImportSelector().selectImports(configClass.getMetadata());
8.               processImports(configClass,asSourceClass(configClass), asSourceClasses(imports), false);
9.           }
10.          catch(BeanDefinitionStoreException ex) {
11.              throwex;
12.          }
13.          catch(Throwable ex) {
14.              thrownew BeanDefinitionStoreException(……略);
15.          }
16.      }
17. }

          依次处理所有实现DeferredImportSelector接口的ImportSelector类。

        第一次循环时,只有一个类,即由SofaBootRpcDemoApplication类导入的EnableAutoConfigurationImportSelector类,调用其selectImports方法,解析出所有支持自动配置的@Configuration配置类:
1.  public String[]selectImports(AnnotationMetadata metadata) {
2.       if(!isEnabled(metadata)) {
3.           returnNO_IMPORTS;
4.       }
5.       try{
6.           AnnotationAttributesattributes = getAttributes(metadata);
7.           List<String> configurations =getCandidateConfigurations(metadata,
8.                   attributes);
9.           configurations= removeDuplicates(configurations);
10.          Set<String>exclusions = getExclusions(metadata, attributes);
11.          configurations.removeAll(exclusions);
12.          configurations= sort(configurations);
13.          recordWithConditionEvaluationReport(configurations,exclusions);
14.          returnconfigurations.toArray(new String[configurations.size()]);
15.      }
16.      catch(IOException ex) {
17.          thrownew IllegalStateException(ex);
18.      }
19. }
          调用getCandidateConfigurations方法,获取所有@Configuration配置类的名字:        
1.  protected List<String>getCandidateConfigurations(AnnotationMetadata metadata,
2.           AnnotationAttributesattributes) {
3.       List<String> configurations =SpringFactoriesLoader.loadFactoryNames(
4.               getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
5.       ……略
6.         return configurations;
7.  }
        通过SpringFactoriesLoader的loadFactoryNames方法,从所有的spring.fatories文件中,加载key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有@Configuration配置类的名字。
1.  public static List<String>loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
2.       StringfactoryClassName = factoryClass.getName();
3.       try{
4.           Enumeration<URL> urls = (classLoader !=null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
5.                   ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
6.           List<String>result = new ArrayList<String>();
7.           while (urls.hasMoreElements()) {
8.               URLurl = urls.nextElement();
9.               Propertiesproperties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
10.              StringfactoryClassNames = properties.getProperty(factoryClassName);
11.          result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
12.          }
13.          returnresult;
14.      }
15.      catch(IOException ex) {
16.          thrownew IllegalArgumentException(……略);
17.      }
18. }
        获取所有@Configuration配置类的名字以后,进行去重、排序、筛选等操作。然后调用processImports方法,处理通过EnableAutoConfigurationImportSelector类导入的@Configuration配置类:
1.  private voidprocessImports(ConfigurationClass configClass, SourceClass currentSourceClass,
2.           Collection<SourceClass>importCandidates, boolean checkForCircularImports) throws IOException {
3.   
4.         ……略
5.       if(checkForCircularImports && isChainedImportOnStack(configClass)) {
6.           ……略
7.       }
8.       else{
9.           this.importStack.push(configClass);
10.          try{
11.              for (SourceClass candidate : importCandidates){
12.                  if(candidate.isAssignable(ImportSelector.class)) {
13.                      //Candidate class is an ImportSelector -> delegate to it to determine imports
14.                      Class<?>candidateClass = candidate.loadClass();
15.                      ImportSelectorselector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
16.                      ParserStrategyUtils.invokeAwareMethods(
17.                              selector,this.environment, this.resourceLoader, this.registry);
18.                      if(this.deferredImportSelectors != null && selector instanceofDeferredImportSelector) {
19.                          this.deferredImportSelectors.add(
20.                                  newDeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
21.                      }
22.                      else{
23.                          String[]importClassNames = selector.selectImports(currentSourceClass.getMetadata());
24.                          Collection<SourceClass>importSourceClasses = asSourceClasses(importClassNames);
25.                          processImports(configClass,currentSourceClass, importSourceClasses, false);
26.                      }
27.                  }
28.                  elseif (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
29.                      //Candidate class is an ImportBeanDefinitionRegistrar ->
30.                      //delegate to it to register additional bean definitions
31.                      Class<?>candidateClass = candidate.loadClass();
32.                      ImportBeanDefinitionRegistrarregistrar =
33.                              BeanUtils.instantiateClass(candidateClass,ImportBeanDefinitionRegistrar.class);
34.                      ParserStrategyUtils.invokeAwareMethods(
35.                              registrar,this.environment, this.resourceLoader, this.registry);
36.                      configClass.addImportBeanDefinitionRegistrar(registrar,currentSourceClass.getMetadata());
37.                  }
38.                  else{
39.                      //Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
40.                      //process it as an @Configuration class
41.                      this.importStack.registerImport(
42.                              currentSourceClass.getMetadata(),candidate.getMetadata().getClassName());
43.                      processConfigurationClass(candidate.asConfigClass(configClass));
44.                  }
45.              }
46.          }
47.          catch(BeanDefinitionStoreException ex) {
48.              throwex;
49.          }
50.          catch(Throwable ex) {
51.              ……略
52.          }
53.          finally{
54.              this.importStack.pop();
55.          }
56.      }
57. }

        processImports方法主要逻辑:

        1)   如果导入的配置类实现了DeferredImportSelector接口,则创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待上述processConfigBeanDefinitions方法下一个do{*}while(*)循环中处理。

        2)   如果导入的配置类实现了ImportSelector接口,则调用该类的selectImports方法导入新的@Configuration配置类,并嵌套调用processImports方法,处理导入的@Configuration配置类。

        3)   如果导入的配置类实现了ImportBeanDefinitionRegistrar接口,则创建ImportBeanDefinitionRegistrar实例,并在处理@Configuration配置类过程中,委托该实例注册额外的BeanDefinition。

        4)   如果以上都不是,则导入的配置类为基本的@Configuration配置类,直接调用processConfigurationClass处理,最终具体解析操作在doProcessConfigurationClass方法中实现。

1.  protected final SourceClassdoProcessConfigurationClass(ConfigurationClass configClass, SourceClasssourceClass) throws IOException {
2.       //Recursively process any member (nested) classes first
3.       processMemberClasses(configClass,sourceClass);
4.   
5.       //处理@PropertySource注解
6.       for(AnnotationAttributes propertySource :AnnotationConfigUtils.attributesForRepeatable(
7.               sourceClass.getMetadata(),PropertySources.class, org.springframework.context.annotation.PropertySource.class)){
8.           if(this.environment instanceof ConfigurableEnvironment) {
9.               processPropertySource(propertySource);
10.          }
11.          else{
12.              logger.warn("Ignoring@PropertySource annotation on [" + sourceClass.getMetadata().getClassName()+
13.                      "].Reason: Environment must implement ConfigurableEnvironment");
14.          }
15.      }
16.  
17.      // 处理@ComponentScan注解
18.      Set<AnnotationAttributes>componentScans = AnnotationConfigUtils.attributesForRepeatable(
19.              sourceClass.getMetadata(),ComponentScans.class, ComponentScan.class);
20.      if(!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)) {
21.          for(AnnotationAttributes componentScan : componentScans) {
22.              //The config class is annotated with @ComponentScan -> perform the scanimmediately
23.              Set<BeanDefinitionHolder>scannedBeanDefinitions =
24.                      this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName());
25.              //Check the set of scanned definitions for any further config classes and parserecursively if necessary
26.              for(BeanDefinitionHolder holder : scannedBeanDefinitions) {
27.                  if(ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(),this.metadataReaderFactory)) {
28.                      parse(holder.getBeanDefinition().getBeanClassName(),holder.getBeanName());
29.                  }
30.              }
31.          }
32.      }
33.  
34.      //处理@Import注解
35.      processImports(configClass, sourceClass,getImports(sourceClass), true);
36.  
37.      //处理@ImportResource注解
38.      if(sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
39.          AnnotationAttributesimportResource =
40.                  AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),ImportResource.class);
41.          String[]resources = importResource.getStringArray("locations");
42.          Class<?extends BeanDefinitionReader> readerClass =importResource.getClass("reader");
43.          for(String resource : resources) {
44.              StringresolvedResource = this.environment.resolveRequiredPlaceholders(resource);
45.              configClass.addImportedResource(resolvedResource,readerClass);
46.          }
47.      }
48.  
49.      //处理@Bean方法
50.      Set<MethodMetadata>beanMethods =sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
51.      for(MethodMetadata methodMetadata : beanMethods) {
52.          configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));
53.      }
54.  
55.      ……略
56.  
57.      //No superclass -> processing is complete
58.      returnnull;
59. }

        针对每个@Configuration配置类,依次处理@Configuration配置类中的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean注解,主要解析过程如下:

        1)   @PropertySource处理过程:调用processPropertySource方法处理属性源,在此不详述;

        2)   @ComponentScan处理过程:解析@Configuration配置类中@ComponentScan、@ComponentScans注解,并根据设置的basePackages扫描指定的包路径,并加载、注册所有带有@Component注解及@Component衍生注解(如@Controller、@Service、@Repository、@Configuration等)Java类的Bean定义到Spring应用上下文;

        3)   @Import处理过程:参考上述processImports方法描述。需要注意,在处理某个配置类的@Import注解过程中,如果发现@Import导入的类实现了DeferredImportSelector接口,则创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待下一次循环处理。以此类推,直至所有的@Configuration配置类加载完毕。例如:在处理SofaBootRpcDemoApplication的@Import注解时,由于在SofaBootRpcDemoApplication类@SpringBootApplication注解中引用了@EnableAutoConfiguration注解,而它又引用了@Import(value={EnableAutoConfigurationImportSelector.class})。由于EnableAutoConfigurationImportSelector实现了DeferredImportSelector接口,所以在此创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待所有@Configuration注解类解析完成以后再处理。

        4)   @ImportResource处理过程:解析locations属性,并依次获取locations指定目录下Spring XML配置文件,设置configClass类的importedResource属性;

        5)   @Bean处理过程:读取@Configuration配置类中@Bean注解的方法,并增加到configClass的beanMethod集合。

        至此,处理完现有candidates中所有@Configuration配置类。

        在回看一下processConfigBeanDefinitions方法:
1.  public voidprocessConfigBeanDefinitions(BeanDefinitionRegistry registry) {
2.       List<BeanDefinitionHolder>configCandidates = new ArrayList<BeanDefinitionHolder>();
3.       String[]candidateNames = registry.getBeanDefinitionNames();
4.   
5.       for(String beanName : candidateNames) {
6.           BeanDefinitionbeanDef = registry.getBeanDefinition(beanName);
7.           if(ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
8.                   ConfigurationClassUtils.isLiteConfigurationClass(beanDef)){
9.               ……略
10.          }
11.          elseif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {
12.              configCandidates.add(newBeanDefinitionHolder(beanDef, beanName));
13.          }
14.      }
15.       ……略
16.       ConfigurationClassParser parser = newConfigurationClassParser(
17.              this.metadataReaderFactory,this.problemReporter, this.environment,
18.              this.resourceLoader,this.componentScanBeanNameGenerator, registry);
19.       ……略
20.      do {
21.          parser.parse(candidates);
22.          parser.validate();
23.  
24.          ……略
25.            // Read the model and create beandefinitions based on its content
26.          if(this.reader == null) {
27.              this.reader= new ConfigurationClassBeanDefinitionReader(
28.                      registry,this.sourceExtractor, this.resourceLoader, this.environment,
29.                      this.importBeanNameGenerator,parser.getImportRegistry());
30.          }
31.          this.reader.loadBeanDefinitions(configClasses);
32.  
33.          alreadyParsed.addAll(configClasses);
34.          candidates.clear();
35.          ……略
36.            for (ConfigurationClassconfigurationClass : alreadyParsed) {
37.                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
38.              }
39.              for(String candidateName : newCandidateNames) {
40.                  if(!oldCandidateNames.contains(candidateName)) {
41.                      BeanDefinitionbeanDef = registry.getBeanDefinition(candidateName);
42.                      if(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory) &&
43.                              !alreadyParsedClasses.contains(beanDef.getBeanClassName())){
44.                          candidates.add(newBeanDefinitionHolder(beanDef, candidateName));
45.                      }
46.                  }
47.              }       
48.      }
49.      while (!candidates.isEmpty());
50.  
51.      ……略
52. }

        处理完现有candidates中所有@Configuration配置类以后,调用ConfigurationClassBeanDefinitionReader的loadBeanDefinitions方法加载、注册@Configuration配置类本身及其中的@Bean注解对应的类。

1.  public voidloadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
2.       TrackedConditionEvaluatortrackedConditionEvaluator = new TrackedConditionEvaluator();
3.       for(ConfigurationClass configClass : configurationModel) {
4.           loadBeanDefinitionsForConfigurationClass(configClass,trackedConditionEvaluator);
5.       }
6.  }
        @Configuration配置类的具体加载方法如下:
1.  private void loadBeanDefinitionsForConfigurationClass(ConfigurationClassconfigClass,
2.           TrackedConditionEvaluatortrackedConditionEvaluator) {
3.   
4.       ……略
5.   
6.       if(configClass.isImported()) {
7.           registerBeanDefinitionForImportedConfigurationClass(configClass);
8.       }
9.       for(BeanMethod beanMethod : configClass.getBeanMethods()) {
10.          loadBeanDefinitionsForBeanMethod(beanMethod);
11.      }
12.      loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
13.      loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
14. }

        @Configuration配置类主要加载过程如下:

        1)   把@Configuration配置类自身注册到Spring应用上下文;

        2)   加载@Bean注解对应的BeanDefinition;

        3)   加载@ImportResource注解指定的XML文件或Groovy文件中配置的BeanDefinition;

        4)   从ImportBeanDefinitionRegistrar加载BeanDefinition,如AutoConfigurationPackages;

        在此就不详述注册过程,感兴趣的同学可以自己看看。

        接下来先清空candidates集合,然后从Spring应用上下文中获取所有已经注册的BeanDefinitionNames,然后与已经解析的@Configuration配置类对比,查找未处理的@Configuration配置类,并置入candidates集合,待下一次循环处理。此处循环处理下去,直至所有的@Configuration配置类处理完毕。

        至此,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法执行完毕,加载完所有配置的BeanDefinition。

        不在详述AbstractApplicationContext的refresh方法中其它步骤,感兴趣的同学可以自己看看。

        (七)    Spring应用上下文刷新以后的处理:

        依次调用ApplicationRunner接口和CommandLineRunner接口的实现,完成刷新Spring上下文以后的一些处理操作。

        (八)    终止监听

        依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的finished方法,结束监听器。

        (九)    结束run方法

        调用StopWatch实例的stop方法,结束记录任务的运行时间。

        到此为止,SOFABoot应用启动完成。

三、总结

        通过以上源码分析,可以总结出以下几个部分,作为基于SOFABoot框架进行开发时的基础和扩展的方向。

          (一) EnableAutoConfiguration

        基于SOFABoot框架开发的模块,通过在META-INF/spring.factories文件中配置EnableAutoConfiguration实现SOFABoot模块自动配置功能。

        在SOFABoot应用启动时,自动加载SOFABoot模块META-INF/spring.factories文件中配置的@Configuration配置类,以此作为模块加载的入口,把模块中相关的Bean加载到Spring应用上下文。

        参考配置格式为:

1.  # Auto Configure
2.  org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
3.  org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
4.  org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
5.  org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
6.  org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
7.  org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
8.  org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
9.  org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
10. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
11. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

        这些支持自动配置的Bean在ApplicationContext刷新过程中被注册到Spring应用上下文,具体加载过程参考源码解析部分。

           (二)  ApplicationContextInitializer

        如果希望对Spring应用上下文进行一些个性化的初始化操作,则实现ApplicationContextInitializer接口,在initialize方法中完成个性化的初始化操作。

        在META-INF/spring.factories文件配置ApplicationContextInitializer接口的实现,格式为:

1.  org.springframework.context.ApplicationContextInitializer=\
2.  xxx.yyyy.zzz.XxxInitializer,\
3.  xxx.yyyy.zzz.YyyInitializer

        这些ApplicationContextInitializer接口的实现类在Spring应用上下文准备阶段被调用执行,即SpringApplication的prepareContext方法中。

         (三) ApplicationListener

        如果希望监听Spring应用的事件,当事件发生时,针对事件进行一些个性化操作,则实现ApplicationListener接口,在onApplicationEvent方法中处理发生的Application事件。

        在META-INF/spring.factories文件配置ApplicationListener接口的实现,格式为:

1.  org.springframework.context.ApplicationListener=\
2.  xxx.yyyy.zzz.XxxListener

        当ApplicationEvent事件发生时,这些ApplicationListener接口的实现被调用。

          (四) SpringApplicationRunListener

        如果希望监听SpringBoot的org.springframework.boot.SpringApplication类的run方法,当SpringApplication启动时,进行一些个性化操作,则实现SpringApplicationRunListener接口,针对具体情况实现相应的方法。

1.  public interfaceSpringApplicationRunListener {
2.   
3.  /**
4.   * 当SpringApplication的run方法第一次启动时立即调用。
5.   */
6.  void started();
7.   
8.  /**
9.   * 当Environment准备好时调用,但在ApplicationContext被创建以前。
10.  */
11. void environmentPrepared(ConfigurableEnvironmentenvironment);
12.  
13. /**
14.  * 当Spring应用上下文被创建并准备好时调用,但在sources被加载之前。
15.  */
16. voidcontextPrepared(ConfigurableApplicationContext context);
17.  
18. /**
19.  * 当Spring应用上下文被加载但还没有刷新时调用。
20.  */
21. voidcontextLoaded(ConfigurableApplicationContext context);
22.  
23. /**
24.  * 当SpringApplication的run方法完成时调用。
25.  */
26. void finished(ConfigurableApplicationContextcontext, Throwable exception);
27.  
28. }

          在SpringApplication的run方法中,通过SpringFactoriesLoader类loadFactoryNames方法,查找并加载所有spring.factories文件中定义的SpringApplicationRunListener接口的实现。

        SpringApplicationRunListener接口中各个方法的调用顺序为:

        1.   在SpringApplication的run方法中,调用started方法;

        2.   在SpringApplication的prepareEnvironment方法中,调用environmentPrepared方法;

        3.   在SpringApplication的prepareContext方法中,先调用contextPrepared方法,然后是Spring上下文资源加载,最后调用contextLoaded方法;

        4.   在SpringApplication的run方法中,调用finished方法。

SOFABoot核心能力解析:就绪检查与类隔离实践指南 在Spring Boot微服务开发中,应用启动时依赖未就绪、中间件类库冲突等问题常常导致线上故障,排查成本高昂。SOFABoot作为蚂蚁集团开源的增强框架,基于Spring Boot生态进行深度扩展,通过就绪检查机制确保应用真正具备服务能力后再对外暴露流量,同时借助SOFAArk实现类隔离,从类加载层面解决依赖冲突难题。本文从实际工程视角,剖析SOFABoot就绪检查与类隔离的设计原理、接入步骤和常见问题,帮助开发者理解如何利用这些能力提升微服务稳定性,为生产环境的高可用交付提供参考。 阅读详情

相关推荐

沙发启动:SOFABoot是一个框架,可增强Spring Boot并与之完全兼容,并提供就绪检查,类隔离等功能。

沙发靴 SOFABoot是Ant蚁金服开源的基于Spring Boot的研发框架,它在Spring Boot的基础上,提供了诸如Readiness Check,类隔离,日志空间隔离等等能力。在增强了Spring Boot的同时,SOFABoot提供了让用户可以在Spring Boot中非常方便地使用SOFA中间件的能力。 一,背景 Spring Boot是一个非常优秀的开源框架,可以非常方便地就建造出一个基于Spring的应用程序,但是在使用过程中,还是会遇到一些问题: Spring Boot提供了一个基础的健康检查的能力,中间件和应用都可以扩展来实现自己的健康检查逻辑。但是Spring Boot的健康检查只有Liveness Check的能力,具备Readiness Check的能力,这样会有比较致命的问题。当一个微服务应用启动的时候,必须要先保证启动后应用是健康的,才可以将上游的流

SOFABoot——基本使用(笔记)

SOFABoot基础

weixin_46949627的博客 4663

UE4_后期处理六—夜视仪、扫描线

观察下面一组蓝图节点的效果:当把角色的自定义深度通道开启:画面效果如图:这样我们就得到了一个这样的黑白蒙版。

Growthofnotes的博客 1734

【开源项目】SofaBoot实现Spring Bean 异步初始化的源码拆解

【开源项目】SofaBoot实现Spring Bean 异步初始化的源码拆解

秋装什么的博客 895

别再为H桥烧MOS管发愁了!手把手教你用IR2104搭建稳定电机驱动(附自举电路详解)

本文详细解析了使用IR2104半桥驱动芯片构建高可靠H桥电机驱动电路的全过程。从芯片内部架构、自举电路原理到PCB布局技巧和实战调试方法,帮助工程师彻底解决MOS管烧毁问题。重点讲解了自举电容选型、死区时间控制等关键设计要点,并附有示波器实测波形分析,是电机驱动设计的实用指南。

我的博客 739

深入解析docx4j:从Word到PDF的高保真转换实战

本文深入解析了如何使用纯Java开源库docx4j实现Word到PDF的高保真转换。针对中文环境,重点讲解了字体映射原理、Linux服务器字体部署方案,并提供了完整的代码示例和配置方法。同时,文章涵盖了表格、图片处理、性能优化及生产环境部署指南,帮助Java开发者构建稳定、可控的文档转换服务。

weixin_29237635的博客 673

sofaboot的启动原理解析

SpringBoot的原理 我们先找到这张springboot的原理图

define_us的专栏 1177

电流互感器的使用分析

有关电流互感器使用的注意事项,回头再看,耳目一新。

qq_46757048的博客 2万+

sofa启动的默认加载参数

sofa启动的默认加载参数  sofa-rpc-5.4.5\core\common\src\main\resources\com\alipay\sofa\rpc\common  rpc-config-default.json 对应配置说明可参考 RpcOptions.java 实际运行中截取结果: java.specification.version=1.8 sun.cpu.isali...

kevin2562的专栏 1993

Python自动化监控:实时捕捉LOF基金溢价套利机会并微信预警

本文详细介绍了如何使用Python构建一个自动化监控系统,实时捕捉LOF基金的溢价套利机会。通过AKShare获取基金数据,结合雪球API计算实时溢价率,并利用企业微信API实现微信推送预警,帮助投资者高效、自动地发现并抓住转瞬即逝的套利机会。

weixin_28327051的博客 525

【智能机器人开发全流程:硬件选型、软件架构与ROS实战,打造高效机器人系统】

通过模块化设计与ROS框架的灵活扩展,可快速搭建适应不同场景的机器人系统。实际开发中需重点关注。

dally2的博客 6038

可以,很强,68行代码实现Bean的异步初始化,粘过去就能用。

前两天在看 SOFABoot 的时候,看到一个让我眼前一亮的东西,来给大家盘一下。SOFABoot,你可能不眼熟,但是没关系,本文也不是给你讲这个东西的,你就认为它是 SpringBoot 的变种就行了。因为有蚂蚁金服背书,所以主要是一些金融类的公司在使用这个框架:官方介绍是这样的:SOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等能力。

Park33的博客 812

QGis二次开发 —— 5.1、基于qgis开发雷达扫描、无人机飞行跟踪等(附:源码及工程)

基于qgis开发雷达扫描、无人机飞行跟踪等

325

SOFABoot源码解析之启动原理(1)-注解分析

        SOFABoot是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等等能力。在增强了 Spring Boot 的同时,SOFABoot 提供了让用户可以在 SpringBoot中非常方便地使用 SOFA 中间件的能力。        为了基于SOFABoot框架进行研发,建...

闲来无事 3368

ESP32设备驱动-TM1637-驱动4位7段数码管

TM1637是一款带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成了MCU数字接口、数据锁存、LED高压驱动、键盘扫描等功能。 TM1637使用DIP20/SOP20封装,主要适用于电磁炉、微波炉、小家电的显示驱动。

视觉与物联智能 2118

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

SOFABoot源码解析之模块化开发

1.SOFABoot源码解析1.1  模块化开发1.1.1 简述        关于SOFABoot模块化开发的文档来自于Alipay开源社区Wiki,链接地址为:        https://github.com/alipay/sofa-boot/wiki/Modular-Development        此处直接引用该文档内容,主要是便于大家理解源码解析部分。1.1.1.1  模块化开发...

闲来无事 3558

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

SOFABoot源码解析之日志空间隔离

一、简述        SOFABoot提供了日志空间隔离能力。        SOFABoot中间件能自动发现SOFABoot应用的日志实现依赖,并独立打印日志,解耦SOFABoot中间件日志和SOFABoot应用日志。        SOFABoot通过其sofa-common-tools包提供日志空间隔离功能。        首先看一下sofa-common-tools包中与日志空间隔离功能...

闲来无事 3719

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

SOFABoot源码解析之JVM服务

1.SOFABoot源码解析1.1  JVM服务1.1.1 服务发布        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot JVM服务发布过程。        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。        RPC案例的SpringXML配置文...

闲来无事 3904

【Java】SOFABoot 启动加速-异步初始化方法

Spring Boot 启动加速 异步初始化方法

闲时不要多想 1245

终极指南:SOFABoot 监控与诊断 - Actuator 端点与健康指标详解

SOFABoot 作为增强 Spring Boot 的框架,提供了丰富的监控与诊断能力,其中 Actuator 端点是实现这一功能的核心组件。本文将详细介绍 SOFABoot Actuator 的关键端点、健康检查机制及实用配置方法,帮助开发者快速掌握服务监控与问题诊断技巧。 ## 📊 SOFABoot Actuator 核心端点概览 SOFABoot 在 Spring Boot Actua

gitblog_01195的博客 1024

SOFARPC源码解析-搭建环境

文档地址:https://www.sofastack.tech 简介摘要 SOFA 是蚂蚁金服自主研发的金融级分布式中间件,包含构建金融级云原生架构所需的各个组件,包括微服务研发框架,RPC 框架,服务注册中心,分布式定时任务,限流/熔断框架,动态配置推送,分布式链路追踪,Metrics监控度量,分布式高可用消息队列,分布式事务框架,分布式数据库代理层等组件,是一套分布式架构的...

weixin_34293902的博客 327

SOFA-MOSN源码解析—配置详解

SOFAMosn是基于Go开发的sidecar,用于service mesh中的数据面代理。官方文档见SOFAMosn,基本架构如下: 一个简单的结合sofa-rpc的例子可参考SOFAMosn代理SOFARPC。 观察到启动mosn形似./main start -c config.json,那么我们可以先从分析配置入手,看看mosn作为数据代理的整个流转过程。 配置初探 config.json...

weixin_33965305的博客 1006

Spring-Boot原理

SpringBoot通过起步依赖简化依赖管理,自动解决版本冲突问题。其核心原理包括:1)组件扫描机制自动发现被@Component标记的类;2)基于反射和Bean工厂创建管理Bean;3)通过@Import动态导入配置类。自动配置基于条件注解实现,读取META-INF/spring下的配置清单加载预设Bean。自定义Starter封装常用配置,实现依赖自动装配。整个过程体现了约定优于配置的思想,显著提升开发效率。

weixin_74354824的博客 755

蚂蚁金服SOFA-Boot整合SOFA-RPC(上篇)

前言 上文介绍了 SOFARPC 的简单使用。在生产环境中,通常会将 SOFARPC 整合到 SpringBoot 中。蚂蚁金服提供了 SOFABoot 框架,SOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等等能力。 在增强了 Spring Boot 的同时,S...

weixin_34292402的博客 1485
上一篇: SOFABoot源码解析之启动原理(1)-注解分析
下一篇: SOFABoot源码解析之日志空间隔离
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任性之闲来无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值