springboot启动源码解析-纯干货扒源码

springboot的启动过程是由一行SpringApplication.run开始的, 其所有的内部细节都隐藏在源码中, 今天一一为大家解开, 过程比较长, 耐心观看相信会有收获的

1. 容器启动

1.1 创建一个SpringApplication

	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

 1.2 开启SpringApplicatioin的run方法, 在这里完成了以下工作

  • 创建监听器
  • 触发监听器
  • 创建上下文
  • 加载BeanDefinition/BeanFactory/BeanPostProcess等等
  • 调用ApplicationContextInitializer, 执行一些初始化代码
  • 刷新上下文, 加载所有的bean实例
public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
        //这里预留了一个空的上下文引用, 并没有真正创建
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
        //@1 这里添加了一下监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            //@2 这里比较重要, 激活了ApplicationEnvironmenPreparedEvent的listener
            //也就是从这一步开始, 转而去创建bootstrap的上下文
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
            //@3 创建了一个上下文
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            //@4 准备上下文, 这里调用applyInitializers会触发ApplicationContextInitializer的 
            //初始化
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            //@5 刷新上下文, 非常重要, 必看, 这里面加载了容器的所有类
			refreshContext(context);
            //预留入口, 空代码
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
            //执行容器中的CommandLineRunner和ApplicationRunner, 默认为空
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

@1 创建Listener详解

a. getRunListeners方法, 内部调用getSpringFactoriesInstances

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

 b.getSpringFactoriesInstances, 这里使用SpringFactoriesLoader的静态方法加载

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

c.进入SpringFactoriesLoader方法 

	public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
	}

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

 debug发现此时的cache已经有值了, 是什么时候加载进去的呢?

 重新回到SpringApplicaton的构造方法, 在这里加载了比较重要的类

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

 进去getSpringFactoriesInstances看一下, 这里其实是同一个方法, 也就是说在new SpringApplication的时候cache中设置了值, 后续直接从cache中取值

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
        //初次运行, result为空

		try {
			Enumeration<URL> urls = (classLoader != null ?
               //FACTORIES_RESOURCE_LOCATION就是"META-INF/spring.factories", 看到这里恍然大悟, 原来就是加载META-INF的启动类
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
                //这里的url会指向spring-boot-2.1.4.RELEASE下的/META-INFO/spring.factories
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                //加载了8个主要的类, 见下图
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
            //放入静态变量cache中
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

好了, 找到了cache的值来源, 我们回到@1开头的地方, 这时候已经加载了ApplicatonListener

@1的流程完成

@2 prepearEnvironment详解

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// @2.1创建environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//@2.2给listener设置environment, 注意这里通知了BootstrapApplicationListener, 也就是会先去初始化BootStrap的加载
        listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

 @2.1 创建environment

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
            //走到这里, 创建了StandardServletEnvironment
			return new StandardServletEnvironment();
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}

这时候已经创建了environment, 而且是bootstrap的environment, 通过debug可以看出来.

所以这时候先暂停一下spring上下文的创建 , 去分析一下bootstrap的上下文, 以及那些配置文件是如何加载的,nacos配置是如何加载的, 和spring的上下文又是什么关系

@3  经过了上面的环境准备与bootstrap步骤, 接下来开始创建spring的上下文 

context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
                    //本次是servlet, 会走到这里
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
                    //如果bootstrap会进入到这里, 创建Default上下文
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

 注意这时候context刚刚创建,此时的parent为null, environment的值是spring环境刚刚创建的. 此时bootstrap的上下文及environment跑到哪里去了呢? 又是如何关联起来的?

 @4 准备上下文prepareContext

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
        //@4.1 这里加载了非常重要的
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

2.监听器启动

首先debug看一下, spring初始化的时候加载了哪些监听器呢?

从上图可以看到, 一共是13个监听器, 其中的第一个就是BootstrapApplicationListener

完整的看一下监听器的加载和调用过程:
SpringApplication.class
private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        //调用监听器的环境准备
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

SpringApplicationRunListeners.class

	public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}
EventPublishingRunListener.class
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}

 SimpleApplicationEventMulticaster.class

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

    @Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}


    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

        
    //随着代码逐行的跟进, 最终进入了这个方法, 这次关注的是BootstrapApplicationListener
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

BootstrapApplicationListener.class
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
		ConfigurableEnvironment environment = event.getEnvironment();
        //检查环境配置中是否存在名为spring.cloud.bootstrap.enabled的属性,如果属性不存在或值为false,则直接返回,不执行后续操作。
		if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
				true)) {
			return;
		}
		//检查属性源中是否包含名为BOOTSTRAP_PROPERTY_SOURCE_NAME的属性源,如果包含,则直接返回,不执行后续操作。
		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
			return;
		}
		ConfigurableApplicationContext context = null;
		String configName = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
		for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
				.getInitializers()) {
			if (initializer instanceof ParentContextApplicationContextInitializer) {
                //如果当前初始化器是ParentContextApplicationContextInitializer类型,则调用findBootstrapContext方法查找引导上下文,并将结果存储在context变量中。


				context = findBootstrapContext(
						(ParentContextApplicationContextInitializer) initializer,
						configName);
			}
		}
		if (context == null) {
			context = bootstrapServiceContext(environment, event.getSpringApplication(),
					configName);
			event.getSpringApplication()
					.addListeners(new CloseContextOnFailureApplicationListener(context));
		}

		apply(context, event.getSpringApplication(), environment);
	}

 经过的分析, 我们看到了spring和springboot的关系, 以及两者是如何完美兼容的

3.bootstrap上下文

通过上面的文章, 我们已经知道Bootstrap的创建是由事件监听器触发的, 入口是onApplicationEvent, 所以我们从listener的入口开始, 循序渐进解开bootstrap的面纱

3.1 BootstrapApplicationListener.onApplicationEvent

public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        //这一步得到已经创建好的environment,具体是哪一步呢, 请翻到@2.1
		ConfigurableEnvironment environment = event.getEnvironment();
		if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
				true)) {
			return;
		}
		// don't listen to events in a bootstrap context
		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
			return;
		}
		ConfigurableApplicationContext context = null;
		String configName = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
		for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
				.getInitializers()) {
            //这里的for循环不会走到, initializer 没有这个类型
			if (initializer instanceof ParentContextApplicationContextInitializer) {
				context = findBootstrapContext(
						(ParentContextApplicationContextInitializer) initializer,
						configName);
			}
		}
		if (context == null) {
            //@1 context为null, 创建bootstrapServiceContext, 代码在下面贴出来了,标记为@2
			context = bootstrapServiceContext(environment, event.getSpringApplication(),
					configName);
			event.getSpringApplication()
					.addListeners(new CloseContextOnFailureApplicationListener(context));
		}

        @3 获取ApplicationContextInitializer并执行
		apply(context, event.getSpringApplication(), environment);
	}

//真正的创建上下文的地方
private ConfigurableApplicationContext bootstrapServiceContext(
			ConfigurableEnvironment environment, final SpringApplication application,
			String configName) {
        //新建了一个bootstrap的environment
		StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
		MutablePropertySources bootstrapProperties = bootstrapEnvironment
				.getPropertySources();
        //移除了bootstrapProperties里的所有内容
		for (PropertySource<?> source : bootstrapProperties) {
			bootstrapProperties.remove(source.getName());
		}
		String configLocation = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
		String configAdditionalLocation = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}");
		Map<String, Object> bootstrapMap = new HashMap<>();
        //这里的configName是"bootstrap"
		bootstrapMap.put("spring.config.name", configName);
		bootstrapMap.put("spring.main.web-application-type", "none");
		if (StringUtils.hasText(configLocation)) {
			bootstrapMap.put("spring.config.location", configLocation);
		}
		if (StringUtils.hasText(configAdditionalLocation)) {
			bootstrapMap.put("spring.config.additional-location",
					configAdditionalLocation);
		}
		bootstrapProperties.addFirst(
				new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
		for (PropertySource<?> source : environment.getPropertySources()) {
			if (source instanceof StubPropertySource) {
				continue;
			}
            //这里塞入了systemProperties与systemEnvironment与bootstrap
			bootstrapProperties.addLast(source);
		}
        //创建了一个Builder, 用于构建一个新的SpringApplication
		SpringApplicationBuilder builder = new SpringApplicationBuilder()
				.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
				.environment(bootstrapEnvironment)
				.registerShutdownHook(false).logStartupInfo(false)
				.web(WebApplicationType.NONE);
		final SpringApplication builderApplication = builder.application();
		if (builderApplication.getMainApplicationClass() == null) {
            //没有执行
			builder.main(application.getMainApplicationClass());
		}
		if (environment.getPropertySources().contains("refreshArgs")) {
            //没有执行
			builderApplication
					.setListeners(filterListeners(builderApplication.getListeners()));
		}
        //又是一个重要的地方, 这里指定了bootstrap自动装配配置文件
		builder.sources(BootstrapImportSelectorConfiguration.class);
        //@2真正的创建上下文, run方法内部其实就是执行了SpringApplication的run
		final ConfigurableApplicationContext context = builder.run();
		context.setId("bootstrap");
		// Make the bootstrap context a parent of the app context
		addAncestorInitializer(application, context);
		bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
		mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
		return context;
	}

 @1 在onApplicationEvent方法中, 调用bootstrapServiceContext创建上下文

@2 真正的创建上下文, 内部会再次走到SpringApplication.run, 加载并刷新上下文

@3 执行bootstrap上下文的initializers

这里有两个initializer, 其中PropertySourceBootstrapConfiguration就是本次的主角, 下面会展开讲解, 其是spring-cloud-context中的类, 也是通过它加载到nacos的bootstrap文件

 接下来, 将再次回到SpringApplication的创建工程. 可以看到spring的加载过程非常非常的长, 能看到这里已经是一种胜利

回顾一下

main -> SpringApplication创建 -> spring启动事件开启 -> boostrap listener触发 -> bootsrap上下创建 ->  再次创建SpringApplication -> 刷新bootstrap上下文 -> bootstrap上下文加载完成, 加载了bootstrap部分类 -> 继续创建spring上下文, 以boostrap上下文作为父上下文 -> 加载其余的类

这样整理一下是不是清晰多了~

 但是springApplication的上下文过程还没有讲解, 接下来是一块硬骨头, 啃下来就可以摸清spring容器是怎么玩转的了 

遗留的一些问题:

  • bootstrapContext与普通的springContext是什么时候建立联系的
  • springcloud的配置文件是何时加载的
  • spring的事件监听器是怎么玩的

4.spring上下文加载

主要分为以下步骤讲解

  1. prepareContext
    - postProcessApplicationContext
    - applyInitializers
    - listeners.contextPrepared
    - getBeanFactory
    - createBeanDefinitionLoader
    - listeners.contextLoaded
            
  2. refreshContext
    - prepareRefresh                         Spring应用上下文启动准备阶段
    - obtainFreshBeanFactory                 BeanFactory创建阶段
    - prepareBeanFactory                     BeanFactory准备阶段
    - postProcessBeanFactory                 BeanFactory后置处理阶段
    - invokeBeanFactoryPostProcessors        BeanFactory注册BeanPostProcessor阶段
    - registerBeanPostProcessors             注册BeanPostProcessor
    - initMessageSource                      初始化内建Bean:MessageSource
    - initApplicationEventMulticaster        初始化内建Bean:Spring事件广播器
    - onRefresh                              Spring应用上下文刷新阶段,由子类实现
    - registerListeners                      Spring事件监听器注册阶段
    - finishBeanFactoryInitialization        实例化所有剩余的(非lazy init)单例
    - finishRefresh                          刷新完成阶段
  3. afterRefresh

4.1 prepareContext

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
        //将ConfigurableEnvironment设置到ConfigurableApplicationContext中,用于配置应用程序的环境。
		context.setEnvironment(environment);
        //@1上下文后置处理器
		postProcessApplicationContext(context);
        //@2调用ApplicationContextInitializer初始化
		applyInitializers(context);
        //@3通知SpringApplicationRunListeners实例,应用程序上下文已准备就绪。
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //向应用程序上下文的bean工厂注册名为springApplicationArguments的单例bean,用于存储应用程序的参数。
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
        //如果bean工厂是DefaultListableBeanFactory的实例,则设置是否允许覆盖bean定义。
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		//@5获取所有应用程序的源,通常是用于启动Spring Boot应用程序的类。
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
        //@6加载应用程序的源到应用程序上下文中。
		load(context, sources.toArray(new Object[0]));
        //通知SpringApplicationRunListeners实例,应用程序上下文已加载完成。
		listeners.contextLoaded(context);
	}

@2 看一下Initiallizer都有哪些

@3通知SpringApplicationRunListeners实例,后续可以结合实际讲解spring中的事件节使用, spring也封装的很好, 开箱即用, 这里简单看一下有哪些事件节监听

@ 5 加载源, 当springboot项目刚启用时, 这里的source只有一个, 那就是org.springframework.cloud.bootstrap.BootstrapImportSelectorConfiguration

, 根据名字我们可以猜测到, springboot的很多启动类是从这里被载入的

这里可以再看一下第二次加载到的时候, 就变成了Main类

@6随着第五步完成, 这里开始加载BootstrapImportSelectorConfiguration

protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug(
					"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
        //这里的context也是BeanDefinitionLoader , 所以此处的loader=context
		BeanDefinitionLoader loader = createBeanDefinitionLoader(
				getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
            //为加载器配置环境
			loader.setEnvironment(this.environment);
		}
        进入BeanDefinitionLoader加载
		loader.load();
	}

BeanDefinitionLoader.class

	private int load(Class<?> source) {
		if (isGroovyPresent()
				&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
			// Any GroovyLoaders added in beans{} DSL can contribute beans here
			GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
					GroovyBeanDefinitionSource.class);
			load(loader);
		}
		if (isComponent(source)) {
            //进入这里, 通过AnnotatedBeanDefinitionReader加载
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}

	private boolean isComponent(Class<?> type) {
		// This has to be a bit of a guess. The only way to be sure that this type is
		// eligible is to make a bean definition out of it and try to instantiate it.
		if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
			return true;
		}
		// Nested anonymous classes are not eligible for registration, nor are groovy
		// closures
		if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()
				|| type.getConstructors() == null || type.getConstructors().length == 0) {
			return false;
		}
		return true;
	}
AnnotatedBeanDefinitionReader.class
	public void register(Class<?>... annotatedClasses) {
		for (Class<?> annotatedClass : annotatedClasses) {
            //进入下一步
			registerBean(annotatedClass);
		}
	}

	public void registerBean(Class<?> annotatedClass) {
        //进入下一步
		doRegisterBean(annotatedClass, null, null, null);
	}

        
    //注册bootstrapImportSelectorConfiguration
    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(instanceSupplier);
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        //工具类加载, 这里的进入真正的加载
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

到此, 又进入了spring的核心区别, BeanDefinition的加载和装配, 这一章不深入展开, 以后再单独讲解Bean容器是如何装载各个bean的

好的,很高兴为您解答这个问题。 在深度学习中,数据增强是一种常用的技术,它可以通过对原始数据进行变换、裁剪、旋转、翻转等操作,来扩充训练集,从而提高模型的泛化能力和鲁棒性。在图像领域,常用的数据增强方法包括随机裁剪、随机旋转、随机翻转、色域变换等。下面,我将为您介绍如何使用 Python 对图像进行随机数据增强。 1. 随机裁剪 随机裁剪是一种简单而有效的数据增强方法,它可以通过对原始图像进行随机裁剪,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机裁剪。 ```python from PIL import Image import random def random_crop(img, crop_size): w, h = img.size left = random.randint(0, w - crop_size) top = random.randint(0, h - crop_size) right = left + crop_size bottom = top + crop_size return img.crop((left, top, right, bottom)) ``` 2. 随机旋转 随机旋转是一种常用的数据增强方法,它可以通过对原始图像进行随机旋转,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机旋转。 ```python from PIL import Image import random def random_rotate(img, angle_range): angle = random.uniform(-angle_range, angle_range) return img.rotate(angle) ``` 3. 随机翻转 随机翻转是一种简单而有效的数据增强方法,它可以通过对原始图像进行随机翻转,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机翻转。 ```python from PIL import Image import random def random_flip(img, flip_prob): if random.random() < flip_prob: return img.transpose(Image.FLIP_LEFT_RIGHT) return img ``` 4. 色域变换 色域变换是一种常用的数据增强方法,它可以通过对原始图像进行色彩变换,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现色域变换。 ```python from PIL import Image import random def random_color(img, color_range): r, g, b = img.split() r = r.point(lambda i: i + random.randint(-color_range, color_range)) g = g.point(lambda i: i + random.randint(-color_range, color_range)) b = b.point(lambda i: i + random.randint(-color_range, color_range)) return Image.merge('RGB', (r, g, b)) ``` 以上就是使用 Python 进行随机数据增强的一些常用方法,希望对您有所帮助。如果您有任何问题,请随时联系我。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值