工作中对于我们java开发者来说最经常使用的框架就是spring了,那么了解spring的基础原理对于我们的能力提升具有很大的好处。首先,作为框架首先它肯定还是从java基础演变而来,也就是说框架的代码都是基于我们日常使用的继承、多态已经各种设计模式的整合而抽取出来的一套规范。我们开发项目要想搭乘spring的快车就需要按规范做事,按规范开发。那么规范的熟悉程度就等价于项目质量的高低。当然框架的基础都是好的idea,好的idea不仅兼容一切还简单。这就和物理界的大一统理论一样。怎么做不重要,重要的是怎么兼容一切,因为做的办法会有无限种。实在无法实现也可以同缩小解的范围。废话不说了。让我们开启spring的流浪之旅。
工作中因为使用的是springboot,因此我们就直接从springboot来分析spring。
public static void main(String[] args) {
SpringApplication.run(SimpleAdminService.class, args)
}
我们看到是springAppcliatIion这个类启动的,我们跟踪一下
public static ConfigurableApplicationContext run(Class primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
发现在第二个run方法的时候进行调用了springApplication的初始化方法。那么在初始化方法中又做了哪些事情?
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();//打印sprnigboot的启动标志的模式
this.bannerMode = Mode.CONSOLE;//日志的标志
this.logStartupInfo = true;//启动命令的标志
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//用来判断是那种应用,对后边创建application的类型有作用this.webApplicationType = WebApplicationType.deduceFromClasspath();//加载spring.factories中注册的bean
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));//读取spring.factories文件加载applicationListener类然后实例化并返回
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
发现在合理做了一些配置,主要是针对springApplication这个类的。那么是如何读这个配置文件的?跟踪代码,这块的代码主要是将spring.factories中注册的bean全部放到缓存中。private CollectiongetSpringFactoriesInstances(Classtype) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
private CollectiongetSpringFactoriesInstances(Classtype) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private CollectiongetSpringFactoriesInstances(Classtype, Class[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Setnames =new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
Listinstances =this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
private ListcreateSpringFactoriesInstances(Classtype, Class[] parameterTypes, ClassLoader classLoader, Object[] args, Setnames) {
Listinstances =new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable var12) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
}
}
return instances;
}
private static Map<string< span="">, List> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<string< span="">, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumerationurls = classLoader !=null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
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 factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
继续跟踪代码。进入了springApplication类的核心区。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();//创建一个上下文,这个是接口。
ConfigurableApplicationContext context = null;
CollectionexceptionReporters =new ArrayList();
this.configureHeadlessProperty();//拿到spring.factories文件,找到获取springApplication的监听类。
SpringApplicationRunListeners listeners = this.getRunListeners(args);//启动spring.factories中的bean
listeners.starting();
Collection exceptionReporters;
try {//将传入的参数进行封装
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//将传入的参数封装为configurableEnvironment
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);//打印启动的环境spring.profiles.active
Banner printedBanner = this.printBanner(environment);//创建ioc容器
context = this.createApplicationContext();//处理异常的,也是从spring.factories中读取的。
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);//ioc的前置处理
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);//核心方法
this.refreshContext(context);//ioc的后置处理,但是为空
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//对监听的器发布已经启动的消息
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {//向监听器广播项目已经启动的消息
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
那么getRunListeners是做什么的?
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
我们能发现和之前获取spring.factories的过程一样,但获取的是ApplicationListen的类。那么我们看一下listeners.starting();
public void starting() {
Iterator var1 = this.listeners.iterator();
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.starting();
}
}
发现通过轮询所有的listener,然后逐个去调用onApplicationEvent方法。那么如何自定义和一个springBootApplicationListen?
@Data
@AllArgsConstructor
public class TestApplicationListener implements SpringApplicationRunListener {
public TestApplicationListener(SpringApplication application, String[] args){
System.out.println("constructor");
}
@Override
public void starting() {
System.out.println("start");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println(environment.toString());
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("拿到容器");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("容器加载完毕");
}
@Override
public void started(ConfigurableApplicationContext context) {
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("run方法");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("失败");
}
}
在META-INF的spring.factories中加入该监听器的地址
org.springframework.boot.SpringApplicationRunListener=\
com.scaffold.simple.admin.TestApplicationListener
启动的效果
通过例子,我们知道spring是轮询的找到注册到spring.factories中的applicationrunlisenner,然后调用starting方法。
我们看一下prepareEnvironment方法
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());//广播配置准备结束的消息
listeners.environmentPrepared((ConfigurableEnvironment)environment);//将配置绑定到springapplication
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
在createApplicationContext创建ioc容器的时候,因为的springApplication构造方法的时候已经决定了webapplicationType,因此这块就直接创建了。咱们一般web都是走的AnnotationConfigReactiveWebServerApplicationContext的容器。
protected ConfigurableApplicationContext createApplicationContext() {
Class contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
在前置处理的是怎么处理的呐?
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {//ioc容器中设置envirment
context.setEnvironment(environment);//给ioc容器设置一些辅助类
this.postProcessApplicationContext(context);//将spring.factories中读取的实现了ApplicationContextInitializer并初始化到容器中
this.applyInitializers(context);//对监听器进行广播
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);//打印spring.profiles.active
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//这里的source就是启动类。
Setsources =this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));//容器广播
listeners.contextLoaded(context);
}
通过跟踪this.load方法
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//创建beanDefinitionLoader
BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {//设置bean名称的生成器
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
加载的最后大概是将启动类注册到beandefinition中了。
private int load(Class source) {
if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
this.load(loader);
}
if (this.isComponent(source)) {
this.annotatedReader.register(new Class[]{source});
return 1;
} else {
return 0;
}
}
通过一大篇的load,然后通过静态方法将该bean注册到了容器中了。
声明:以上代码解析为个人观点,不对之处,希望指正。谢谢!