当前位置:   article > 正文

Spring Boot笔记_collectors.collectingandthen

collectors.collectingandthen

Spring Boot

Spring Boot概述

  • spring能干什么

    • 微服务
    • 响应式编程
    • 云开发(springCloud)
    • web
    • 无服务?
    • 事件驱动
    • Batch(任务处理)
  • Spring Boot2

    • Servlet
    • Reactive(响应式)
  • Spring Boot能干什么

    • 创建独立的应用
    • 内置了tomcat、等
    • dependencies start
    • 自动配置
    • 监控
    • 不需要代码、xml配置文件
  • Spring Boot 特性

    • 依赖管理
    • starters:spring-boot-starter-* spring-boot-starter(包含autoconfigure、yaml、)
    • 默认/自定义包扫描
    • 常用组件介绍

启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zskjxyun-1629195611467)(/Users/apple/Library/Application Support/typora-user-images/image-20210802173621401.png)]

注解

配置应用上下文

ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class, args);
				//打印上下文的所有的bean
        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
  • 1
  • 2
  • 3
  • 4
  • 5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gAitteaQ-1629195611468)(/Users/apple/Library/Application Support/typora-user-images/image-20210802173908825.png)]

@SpringBootApplication

  • (scanBasePackages = “com.fan”):扫描包

  • run方法

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    		ConfigurableApplicationContext context = null;
    		configureHeadlessProperty();
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting(bootstrapContext, this.mainApplicationClass);
    		try {
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    			configureIgnoreBeanInfo(environment);
    			Banner printedBanner = printBanner(environment);
    			context = createApplicationContext();
    			context.setApplicationStartup(this.applicationStartup);
    			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    			refreshContext(context);
    			afterRefresh(context, applicationArguments);
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, listeners);
    			throw new IllegalStateException(ex);
    		}
    
    		try {
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, null);
    			throw new IllegalStateException(ex);
    		}
    		return context;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

@SpringBootApplication中的注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  • 1
  • 2
  • 3
  • 4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPH8HxpQ-1629195611470)(/Users/apple/Library/Application Support/typora-user-images/image-20210802174308779.png)]

@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
image-20210802193359811

作用:表示该注解标注的类是一个配置类

@ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan 
  • 1
  • 2
  • 3
  • 4
  • 5
image-20210802193850930

作用:表示有一个组件扫描的作用

@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
image-20210802194135564
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage 
  • 1
  • 2
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}

	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bq7Uk2sS-1629195611472)(/Users/apple/Library/Application Support/typora-user-images/image-20210802194538781.png)]

作用:对应的是扫描路径:new PackageImports(metadata).getPackageNames() = com.muse.springbootdemo

@Import(AutoConfigurationImportSelector.class)

自动注入选择器

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  • 1

SpringFactoriesLoader类

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

加载原理

  • 要去查找所有项目依赖的jar包
  • 去遍历的寻找每一个jar包META-INF/spring.factories路径下的文件(有的jar包有,有的没有)
  • 找到所有的spring.factories文件,把他们加载到ioc容器中(作为候选的bean)
  • 加载可以加载的bean

@Import

import是全路径名加载到ioc容器中

@Import({Soldier.class, Gun.class})
  • 1
image-20210802192159307

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dG5Ncmpn-1629195611472)(/Users/apple/Library/Application Support/typora-user-images/image-20210802192234328.png)]

@ConfigurationProperties

@ConfigurationProperties(prefix = "muse")//前缀muse
  • 1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCsuhQ38-1629195611473)(/Users/apple/Library/Application Support/typora-user-images/image-20210802193112102.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v2usj3WH-1629195611475)(/Users/apple/Library/Application Support/typora-user-images/image-20210802193154904.png)]

SpringBoot原理

@SpringBootApplication
  public class SpringbootDemoApplication {
    public static void main(String[] args) {
      SpringApplication.run(SpringbootDemoApplication.class, args);
       }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

run

// eg1: primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class}  args={}
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
  • 1
  • 2
  • 3
  • 4
  • 创建SpringApplication

    SpringApplication springApplication = new SpringApplication(primarySources);
    
    • 1
    • 七个步骤,全是初始化属性

      // eg1: resourceLoader=null   primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class}
      	@SuppressWarnings({ "unchecked", "rawtypes" })
      	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
      
      		// eg1: resourceLoader=null
      		this.resourceLoader = resourceLoader;
      		Assert.notNull(primarySources, "PrimarySources must not be null");
      
      		// eg1: primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class}
      		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
      
      		// eg1: webApplicationType=WebApplicationType.SERVLET
      		this.webApplicationType = WebApplicationType.deduceFromClasspath();
      
      		// eg1: bootstrapRegistryInitializers=new ArrayList<>();
      		this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
      
      		// eg1: initializers=7个ApplicationContextInitializer的实现类
      		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
      
      		// eg1: listeners=8个ApplicationListener的实现类
      		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
      
      		// eg1: mainApplicationClass=com.muse.springbootdemo.SpringbootDemoApplication.class
      		this.mainApplicationClass = deduceMainApplicationClass();
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
    • 初始化resourceLoader(资源加载器)

      resourceLoader=null
      
      • 1
    • 初始化Set<Class<?>> primarySources;(主要的资源类集合)

       primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class}
      
      • 1
    • 初始化WebApplicationType webApplicationType(web应用类型 3 种)

      通过classpath判断我们现在正在使用的是哪一种web应用类型?

      // eg1: 以开启spring mvc为例
      	static WebApplicationType deduceFromClasspath() {
      		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) // eg1: 找不到org.springframework.web.reactive.DispatcherHandler类,则第一个判断返回false
      				&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
      				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      			return WebApplicationType.REACTIVE;
      		}
      
      		// eg1: SERVLET_INDICATOR_CLASSES={"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"}
      		for (String className : SERVLET_INDICATOR_CLASSES) {
      			// eg1: Servlet和ConfigurableWebApplicationContext都是存在的,所以都返回true
      			if (!ClassUtils.isPresent(className, null)) {
      				return WebApplicationType.NONE;
      			}
      		}
      
      		// eg1: return WebApplicationType.SERVLET;
      		return WebApplicationType.SERVLET;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      webApplicationType=WebApplicationType.SERVLET
        
        /**
      	 * The application should not run as a web application and should not start an
      	 * embedded web server.
      	 * 不是web应用
      	 */
      	NONE,
      
      	/**
      	 * The application should run as a servlet-based web application and should start an
      	 * embedded servlet web server.
      	 * MVC
      	 */
      	SERVLET,
      
      	/**
      	 * The application should run as a reactive web application and should start an
      	 * embedded reactive web server.
      	 * 响应式编程
      	 */
      	REACTIVE;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    • 初始化List bootstrapRegistryInitializers (引导程序注册的初始化)

      从MEAT-INF/spring.factories配置文件中,获取BootStrapper.class和BootStrapRegistryInitaializer.class这两个配置类型,然后合并存储到bootstraoRegistryInitializers中。

      private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
      		ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
      		// eg1: getSpringFactoriesInstances(Bootstrapper.class)返回空的List,
      		//      说明Bootstrapper在spring.factories的配置文件中也没有配置,所以lambda表达式对返回值什么都没处理
      		getSpringFactoriesInstances(Bootstrapper.class).stream().map((bootstrapper) ->
      				((BootstrapRegistryInitializer) bootstrapper::initialize)).forEach(initializers::add);
      
      		// eg1: getSpringFactoriesInstances(BootstrapRegistryInitializer.class) 返回空的List
      		//      说明BootstrapRegistryInitializer在spring.factories的配置文件中也没有配置
      		initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
      
      		// eg1: 返回new ArrayList<>();
      		return initializers;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      bootstrapRegistryInitializers=new ArrayList<>();
      
      • 1
    • getSpringFactoriesInstances

      BootStrapper.class和BootStrapRegistryInitaializer.class都通过上面的方式初始化

      ApplicationContextInitializer.class 和 ApplicationListener.class都通过上面的方式初始化

    • 初始化 List<ApplicationContextInitializer<?>> initializers(应用上下文的初始化)

    • 初始化 List<ApplicationListener<?>> listeners(监听器的初始化)

    • 初始化 Class<?> mainApplicationClass(主应用类)

      private Class<?> deduceMainApplicationClass() {
      		try {
      			/** 通过new RuntimeException().getStackTrace()获得调用栈轨迹的数组 */
      			// eg1: stackTrace.size()= 6
      			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      			for (StackTraceElement stackTraceElement : stackTrace) {
      				if ("main".equals(stackTraceElement.getMethodName())) {
      					// eg1: stackTraceElement.getClassName()=com.muse.springbootdemo.SpringbootDemoApplication
      					return Class.forName(stackTraceElement.getClassName());
      				}
      			}
      		}
      		catch (ClassNotFoundException ex) {
      			// Swallow and continue
      		}
      		return null;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      Class<?> mainApplicationClass = com.muse.springbootdemo.SpringbootDemoApplication.class

    • SpringFactoriesLoader

      // eg1: classLoader=ClassLoaders$AppClassLoader@1967
      	/**
      	 * 处理流程:
      	 * 1> 读取所有依赖jar包中,每一个存在META-INF/spring.factories的配置文件内容;
      	 * 2> 将配置文件中的内容维护到Map<String, List<String>> result中,如果key相同,则value取合集;
      	 * 3> 将result维护到缓冲cache中——key=ClassLoader value=result
      	 * 4> 将result作为返回值返回。
      	 */
      	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
      		// eg1: cache.size()=0
      		Map<String, List<String>> result = cache.get(classLoader);
      		// eg1: result=null
      		if (result != null) {
      			return result;
      		}
      
      		result = new HashMap<>();
      		try {
      			// eg1: FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
      			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
      			while (urls.hasMoreElements()) {
      				// eg1-1: jar:file:/Users/muse/.m2/repository/org/springframework/boot/spring-boot/2.5.1/spring-boot-2.5.1.jar!/META-INF/spring.factories
      				// eg1-2: jar:file:/Users/muse/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.1/spring-boot-autoconfigure-2.5.1.jar!/META-INF/spring.factories
      				// eg1-3: jar:file:/Users/muse/.m2/repository/org/springframework/spring-beans/5.3.8/spring-beans-5.3.8.jar!/META-INF/spring.factories
      				URL url = urls.nextElement();
      
      				// eg1-1: 通过url获得资源resource,并将spring-boot-2.5.1.jar包下spring.factories文件中的配置信息,加载到properties中。共计13个配置项
      				// eg1-2: 通过url获得资源resource,并将spring-boot-autoconfigure-2.5.1.jar包下spring.factories文件中的配置信息,加载到properties中。共计9个配置项
      				// eg1-3: 通过url获得资源resource,并将spring-beans-5.3.8.jar包下spring.factories文件中的配置信息,加载到properties中。共计1个配置项
      				UrlResource resource = new UrlResource(url);
      				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
      
      				// eg1-1:【仅以第一次循环为例】
      				for (Map.Entry<?, ?> entry : properties.entrySet()) {
      					// eg1-1-1: factoryTypeName="org.springframework.boot.diagnostics.FailureAnalysisReporter"
      					String factoryTypeName = ((String) entry.getKey()).trim();
      
      					// eg1-1-1: factoryImplementationNames=String[]{"org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter"}
      					String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
      					for (String factoryImplementationName : factoryImplementationNames) {
      
      						// eg1: result key="org.springframework.boot.diagnostics.FailureAnalysisReporter"
      						//             value={"org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter"}
      						/**
      						 * result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()):
      						 * * 如果<Map>result中不存在指定的key=factoryTypeName,则创建并将value赋值为new ArrayList<>(),再将value值返回。
      						 * * 如果存在指定的key,则直接将value作为返回值。
      						 */
      						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()).add(factoryImplementationName.trim());
      					}
      				}
      			}
      
      			/**
      			 * Replace all lists with unmodifiable lists containing unique elements
      			 *
      			 * collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)方法的使用:
      			 * * 先进行结果集的收集,然后将收集到的结果集进行下一步的处理;即:就是把第一个参数downstream的结果,交给第二个参数Function
      			 * * 函数的参数里面,R apply(T t),也就是将结果设置成t。
      			 */
      			// eg1: 将value中的ArrayList类型,由UnmodifiableRandomAccessList封装一层。
      			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
      					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
      
      			/**
      			 * 为什么result.size()的最终大小为18个配置项?
      			 * ---------------------------------------------------------------------------------------------
      			 * 【spring-boot-2.5.1.jar】 配置项key:共13个
      			 * org.springframework.boot.logging.LoggingSystemFactory
      			 * org.springframework.boot.env.PropertySourceLoader
      			 * org.springframework.boot.context.config.ConfigDataLocationResolver
      			 * org.springframework.boot.context.config.ConfigDataLoader
      			 * org.springframework.boot.SpringApplicationRunListener
      			 * org.springframework.boot.SpringBootExceptionReporter
      			 * org.springframework.context.ApplicationContextInitializer
      			 * org.springframework.context.ApplicationListener
      			 * org.springframework.boot.env.EnvironmentPostProcessor
      			 * org.springframework.boot.diagnostics.FailureAnalyzer
      			 * org.springframework.boot.diagnostics.FailureAnalysisReporter
      			 * org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector
      			 * org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector
      			 *---------------------------------------------------------------------------------------------
      			 * 【spring-boot-autoconfigure-2.5.1.jar】 配置项key:共9个,重复5个
      			 * (重复)org.springframework.context.ApplicationContextInitializer
      			 * (重复)org.springframework.context.ApplicationListener
      			 * (重复)org.springframework.boot.env.EnvironmentPostProcessor
      			 * org.springframework.boot.autoconfigure.AutoConfigurationImportListener
      			 * org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
      			 * org.springframework.boot.autoconfigure.EnableAutoConfiguration
      			 * (重复)org.springframework.boot.diagnostics.FailureAnalyzer
      			 * org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider
      			 * (重复)org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector
      			 *---------------------------------------------------------------------------------------------
      			 * 【spring-beans-5.3.8.jar】 配置项key:共1个
      			 * org.springframework.beans.BeanInfoFactory
      			 *
      			 * 【总计配置项key】13 + 4 + 1 = 18个
      			 */
      			// eg1: classLoader=ClassLoaders$AppClassLoader@1967   result.size()=18
      			cache.put(classLoader, result);
      		}
      		catch (IOException ex) {
      			throw new IllegalArgumentException("Unable to load factories from location [" +
      					FACTORIES_RESOURCE_LOCATION + "]", ex);
      		}
      
      		// eg1: result.size()=18
      		return result;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
  • 调用SpringApplication实例去运行(run)

    springApplication.run(args)
    
    • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/479558
推荐阅读
相关标签
  

闽ICP备14008679号