SpringBoot-源码阅读

从SpringApplication.run方法阅读,本文中编号顺序与代码执行顺序完全相同

0.SpringApplication类deduceWebEnvironment方法

private boolean deduceWebEnvironment() {
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			//就是通过class.forname判断,如果抛异常了,就说明不包含该类
			if (!ClassUtils.isPresent(className, null)) {
				return false;
			}
		}
		return true;
	}

说白了就是判断当前这个项目是不是一个web项目,判断的方式很简单,如果引用的jar包中,包含了javax.servlet.Servlet或者spring自己的ConfigurableWebApplicationContext,则认为是个web项目,将是不是的结果存到SpringApplication类webEnvironment中,true是web项目flase不是web项目

1.SpringFactoriesLoader类loadFactoryNames方法
(也可参考这篇文章)

//此时参数factoryClass=ApplicationContextInitializer.class,spring写死的,从run方法跟踪可以很快发现
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		try {
			//获取所有引用jar包classpath下的MATE-INF文件夹的spring.factories文件
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			//循环创建每个spring.factories文件的Properties实例,并且从这些实例中只找key
			//为ApplicationContextInitializer的,取其value值,因为value值多个的时候,是用逗号分隔的,所以使用逗号拆分,然后添加到一个list中,最后返回
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				String factoryClassNames = properties.getProperty(factoryClassName);
				result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
					"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

首先获取_所有引用jar包classpath下_的MATE-INF文件夹的spring.factories(可以认为就是properties)文件,读取其内容,如果key值是ApplicationContextInitializer,则取其value,并放到一个list中,返回,之后会用到value(其实这些value都是接口ApplicationContextInitializer的实现类)

注:在spring cloud中,每个组件的jar包,都会有spring.factories文件,比如eurake的jar包下,存在该文件,记录的是关于eurake相关的内容,zuul的jar包下,存在该文件,记录的是关于zuul的相关内容

2.SpringApplication类createSpringFactoriesInstances方法

//没什么好说的,就是根据全限定名,反射创建对象,放到List里,然后返回
//type=ApplicationContextInitializer.class
//names=上个方法的返回值
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<T>(names.size());
		for (String name : names) {
			try {
				//通过反射创建个对象
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				//判断上边这个对象是不是ApplicationContextInitializer接口的实现类
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

根据1的返回值,通过反射,创建ApplicationContextInitializer接口的实例,无其他操作

3.SpringApplication类addInitializers方法

//initializers=2的返回值
public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
		this.initializers.addAll(initializers);
}

该方法就是将2的返回值保存到SpringApplication类的initializers中

4.SpringApplication类setListeners方法

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

该方法重复123的步骤,不过123是加载ApplicationContextInitializer实例,而本方法是加载ApplicationListener接口的实例,然后赋值到SpringApplication类listeners属性中

5.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;
}

判断程序执行到此为止,是不是从某个类的main方法开始的,如果是,则返回该class对象(也就是springboot的启动类),并将该class对象赋值到SpringApplication类mainApplicationClass属性中

6.SpringApplication类configureHeadlessProperty()方法

private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

这个没什么好说的,就是将程序设置成headless模式,相当于代码这样写

System.setProperty("java.awt.headless","true");

7.SpringApplication类getRunListeners方法

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

再次使用SpringFactoriesLoader.loadFactoryNames()方法,将META-INF/spring.factories文件中SpringApplicationRunListener接口的实现类都取出来,之后调用SpringApplicationRunListeners(注意有S)的starting()方法,此处就是观察者模式,for循环调用每一个SpringApplicationRunListener(没有S)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值