1. Springboot 源码解读:入口类

本文基于springboot 2.1.3版本进行解析。

Spring Boot 的入口类

@SpringBootApplication
public class SpringbootSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootSecurityApplication.class, args);
    }

}

如上是最简单的springboot的入口类
@SpringBootApplication注解启动spring boot特性,通过run方法来启动spring boot项目

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

可以看到用primarySources实例化SpringApplication对象。再调用实例的run方法来进行启动。

SpringApplication的实例化

public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		// 1. 资源加载器初始化为null
		this.resourceLoader = resourceLoader;
		// 2 传入的primarySources类不能为空
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// 3 传入的primarySources去重
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 4 根据类的路径判断当前 WEB 应用类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 5 设置上下文初始类
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		// 6 设置监听
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//7 主入口应用类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

实例化的过程,写在代码的注释中。

ApplicationContextInitializer 是什么?

用来初始化指定的 Spring 应用上下文,如注册属性资源、激活 Profiles 等。

   setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));

	public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<>();
		this.initializers.addAll(initializers);
	}

setInitializers 方法比较简单,初始化一个集合,并将ApplicationContextInitializer的初始化类加入集合

如何通过工厂类获取所有的初始化类实例?

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// 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;
	}
  • 获取当前的classLoader
	public ClassLoader getClassLoader() {
		if (this.resourceLoader != null) {
			return this.resourceLoader.getClassLoader();
		}
		return ClassUtils.getDefaultClassLoader();
	}

resourceLoader 当前设置为null,类加载器为默认的类加载器;默认的类加载器,是当前线程的类加载器

  • 获取ApplicationContextInitializer 的实例名称集合并去重

    根据类路径下的META-INF/spring.factories文件解析获取ApplicationContextInitializer接口的所有配置类路径名称
    文件的内容如下:

    # Application Context Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
    org.springframework.boot.context.ContextIdApplicationContextInitializer,\
    org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
    org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
    
  • 根据类路径创建初始化器实例列表

  • 初始化器实例列表排序

  • 返回初始化器实例列表

ApplicationListener 监听器

监听器是用来处理application 时间的。它继承了EventListener和ApplicationEvent。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
		this.listeners = new ArrayList<>();
		this.listeners.addAll(listeners);
	}

监听器的设置同ApplicationContextInitializer 一样,也是通过加载META-INF/spring.factories文件中的监听器instances,最终放入集合中

获取主入口应用类

创建一个运行时异常栈,遍历异常栈中的方法名;如果存在main的方法,则返回类,即为入口应用类的名字

	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;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值