理解 springBoot-springApplication之准备阶段

SpringApplication 基本使用

SpringApplication 运行
SpringApplication.run(SpringBootApplication.class, args)
自定义 SpringApplication
通过 SpringApplication API 调整
SpringApplication springApplication = new SpringApplication(DiveInSpringBootApplication.class);
Set<String> sources = new HashSet<>();
sources.add(SpringbootdemoApplication.class.getName());

SpringApplication springApplication = new SpringApplication();
/**
		 * a class name, package name, or an XML resource location.
		 */
springApplication.setSources(sources);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
springApplication.setWebApplicationType(WebApplicationType.NONE);
springApplication.setAdditionalProfiles("dev");
springApplication.setHeadless(true);
springApplication.run(args);
通过 SpringApplicationBuilder API 调整
new SpringApplicationBuilder(DiveInSpringBootApplication.class)
        .bannerMode(Banner.Mode.CONSOLE)
        .web(WebApplicationType.NONE)
        .profiles("dev")
        .headless(true)
        .run(args);

springApplication准备阶段

SpringApplication构造阶段成为springApplication的准备阶段

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
        //配置spring的源
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //推断web类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //加载ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //加载ApplicationListener 
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //推断main Class
		this.mainApplicationClass = deduceMainApplicationClass();
	}

配置:spring Bean来源

Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并且将配置源解析加载为Spring Bean 定义

BeanDefinitionLoader

	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
        //注解配置
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
        //xml配置
		this.xmlReader = new XmlBeanDefinitionReader(registry);
		if (isGroovyPresent()) {
			this.groovyReader = new GroovyBeanDefinitionReader(registry);
		}
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}
Java 配置 Class

用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如 @Configuration 。

public class CalculateServiceBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(ApplicationBootstrap.class)
    }

    @SpringBootApplication
    public  static  class ApplicationBootstrap{

    }
}
 @SpringBootApplication
public class CalculateServiceBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
    }
}
XML 上下文配置文件

用于 Spring 传统配置驱动中的 XML 文件。

推断

推断 Web 应用类型

根据当前应用 ClassPath 中是否存在相关实现类来推断 Web 应用的类型,包括:

  • Web Reactive: WebApplicationType.REACTIVE

  • Web Servlet: WebApplicationType.SERVLET

  • 非 Web: WebApplicationType.NONE

    参考方法: org.springframework.boot.WebApplicationType#deduceFromClasspath

	static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
推断引导类(Main Class)

根据 Main 线程执行堆栈判断实际的引导类

参考方法: org.springframework.boot.SpringApplication#deduceMainApplicationClass

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

###加载

加载应用上下文初始器 (ApplicationContextInitializer)

利用 Spring 工厂加载机制,实例化 ApplicationContextInitializer 实现类,并排序对象集合。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
    Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(
    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
  • 技术
    • 实现类: org.springframework.core.io.support.SpringFactoriesLoader
    • 配置资源: META-INF/spring.factories
    • 排序: AnnotationAwareOrderComparator#sort
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
自定义ApplicationContextInitializer

@Order(Ordered.LOWEST_PRECEDENCE)
public class HelloWorldAfterApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configure) {
        System.out.println("configure  after "+configure);
    }
}

public class HelloWorldApplicationContextInitializer implements ApplicationContextInitializer,Ordered {
    @Override
    public void initialize(ConfigurableApplicationContext configure) {
        System.out.println("configure  "+configure);
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

META-INF/spring.factories

# Initializers
org.springframework.context.ApplicationContextInitializer=\
cn.zhangspace.springbootdemo.context.HelloWorldApplicationContextInitializer,\
cn.zhangspace.springbootdemo.context.HelloWorldAfterApplicationContextInitializer


加载应用事件监听器( ApplicationListener )

利用 Spring 工厂加载机制,实例化 ApplicationListener 实现类,并排序对象集合

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
# 应用编码的ApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\

# 关于配置文件的ApplicationListener
# application.properties  adn/or  application.yml
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\

# 关于日志的ApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

ApplicationListener 主要关注两个方面

  • Listener关注的事件
  • Listener的优先级别

已LoggingApplicationListener为例

public class LoggingApplicationListener implements GenericApplicationListener {

	public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20;

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationStartingEvent) {
			onApplicationStartingEvent((ApplicationStartingEvent) event);
		}
		else if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		else if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent((ApplicationPreparedEvent) event);
		}
		else if (event instanceof ContextClosedEvent
				&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
			onContextClosedEvent();
		}
		else if (event instanceof ApplicationFailedEvent) {
			onApplicationFailedEvent();
		}
	}
}
spring boot-ApplicationListener 之order重要性

public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {


    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
          String name = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment().getProperty("name");
            System.out.println("配置文件name值为  "+name);

        }
        if (event instanceof ApplicationPreparedEvent) {

        }
    }

    @Override
    public int getOrder() {
        return  Ordered.HIGHEST_PRECEDENCE + 9;
    }
}

META-INF/spring.factories

# Application Listeners
org.springframework.context.ApplicationListener=\
cn.zhangspace.springbootdemo.listener.BeforeConfigFileApplicationListener

application.properties

name=zhangsan

输出结果为 null

在这里插入图片描述

修改BeforeConfigFileApplicationListener 中order

public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {


    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
          String name = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment().getProperty("name");
            System.out.println("配置文件name值为  "+name);

        }
        if (event instanceof ApplicationPreparedEvent) {

        }
    }

    @Override
    public int getOrder() {
        return  Ordered.HIGHEST_PRECEDENCE + 11;
    }
}

结果输出正确

在这里插入图片描述

spring boot 事件

SpringApplicationEvent

public abstract class SpringApplicationEvent extends ApplicationEvent {}
spring事件

ApplicationEvent

public abstract class ApplicationEvent extends EventObject {}

ApplicationContextEvent

public abstract class ApplicationContextEvent extends ApplicationEvent {}
  • ApplicationEvent
    • ApplicationContextEvent
      • ContextClosedEvent
      • ContextRefreshedEvent
      • ContextStartedEvent
      • ContextStoppedEvent
自定义事件监听器
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloworldContextRefreshedApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {


        System.out.println(event.getApplicationContext().getBean("helloWorld"));
        System.out.println("Hello word listener  "+event.getApplicationContext().getId());
    }
}



@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloworldContextStartedEventApplicationListener implements ApplicationListener<ContextStartedEvent> {

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextStartedEvent event) {

        System.out.println("Hello word ContextStartedEvent listener  "+event.getApplicationContext().getId());
    }
}

META-INF/spring.factories

# Application Listeners
org.springframework.context.ApplicationListener=\
cn.zhangspace.springbootdemo.listener.HelloworldContextRefreshedApplicationListener,\
cn.zhangspace.springbootdemo.listener.HelloworldContextStartedEventApplicationListener
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值