SpringBoot
Spring
组件代码轻量级,配置重量级。
- 开始基于xml配置。
- spring 2.5基于主键扫描
- spring 3.0基于java 代码配置
还需要显式配置。比如事物。
项目jar包依赖冲突版本等问题。
SpringBoot
springboot 就是spring 做了一些你用spring 需要配置的东西(tomcat spring配置 web.xml 项目结构)
1 概述
- 最小的阻力下使用spring,简化配置,专注应用程序
@SpringBootApplication(@Configuration@EnableAutoConfiguration @ComponentScan)
(1)Indicates a {@link Configuration configuration} class that declares one or more {@link Bean @Bean} methods。
使用java 配置spring的 java bean,没啥好说的。Indicates that a class declares one or more {@link Bean @Bean} methods may be processed by the Spring container to generate bean definitions service requests for those beans at runtime
(2)triggers {@link EnableAutoConfiguration auto-configuration}
开启许多spring的自动配置,生成必须的Bean.推荐注解加载root 包的类上(main 启动类)。Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined.
(3){@link ComponentScan component scanning}
开启自动配置包组件扫描。
2 源码分析
2.1 初始化、启动
初始化
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication myApplication = new SpringApplication(MyApplication.class);
//定制
myApplication.run();
}
}
SpringApplication 有两个构造方法:
Create a new {@link SpringApplication} instance. The application context will load beans from the specified sources (see {@link SpringApplication class-level} The instance can be customized before calling {@link #run(String...)}.
public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
this.resourceLoader = resourceLoader;
initialize(sources);
}
public SpringApplication(Object... sources) {
initialize(sources);
}
springboot启动过程先要new 一个springboot实例进行初始化配置,
然后调用run 方法。run方法执行前可以做一些定制化的配置比如,添加一些自己的事件监听器(实现 ApplicationListener)实现对ApplicationEvent 的监听处理。
来看一下initialize(sources) 方法。
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
this.webEnvironment = deduceWebEnvironment();
判断是不是一个web项目主要是看javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext这两个类是不是存在。
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
设置初始化器ApplicationContextInitializer,在refresh 之前调用,做一些初始化的工作。 这里读取META-INF/spring.factories下的key为ApplicationContextInitializer的类并实例化。实例化时候通过读取Class 获取构造函数类反射生成。
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);
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;
}
初始设置的 ApplicationContextInitializer有
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
设置默认的所有SpringApplication的事件监听器。读取META-INF/spring.factories下的key为ApplicationListener的类并实例化。
有:
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
注意:如果使用spring cloud 有依赖 spring-cloud-context jar 包的话还会读取其META-INF/spring.factories下的key为ApplicationListener的类并实例化,有两个。
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.context.restart.RestartListener
其中BootstrapApplicationListener 特别重要,他监听spring boot 的环境准备事件ApplicationEnvironmentPreparedEvent,调用 bootstrapServiceContext ()方法,重新调用springboot dr的run(),插入一些spring cloud相关初始化需要的环境,主要应该是一些相关的配置类
this.mainApplicationClass = deduceMainApplicationClass()
找出启动类。
启动
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;//定义spring容器
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);//获取SpringApplicationRunListener
listeners.starting();//监听发送ApplicationStartedEvent 事件
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备额皮质应用环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//打印banner信息
Banner printedBanner = printBanner(environment);
//创建spring容器
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
SpringApplicationRunListeners 类里面就一个log 跟一组SpringApplicationRunListener。加载SpringApplicationRunListener跟加载ApplicationContextInitializer和ApplicationListener的过程一样.
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
说下SpringApplicationRunListener:
/**
* Listener for the {@link SpringApplication} {@code run} method.
* {@link SpringApplicationRunListener}s are loaded via the {@link SpringFactoriesLoader}
* and should declare a public constructor that accepts a {@link SpringApplication}
* instance and a {@code String[]} of arguments. A new
* {@link SpringApplicationRunListener} instance will be created for each run.
*
* @author Phillip Webb
* @author Dave Syer
*/
public interface SpringApplicationRunListener {
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void starting();
/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes.
* @param context the application context or null if a failure occurred before the
* context was created
* @param exception any run exception or null if run completed successfully.
*/
void finished(ConfigurableApplicationContext context, Throwable exception);
}
SpringApplicationRunListener 监听run 方法的执行过程,一共五个处理方法各监听不用的事件event,对应五个步骤。
(1)starting(run方法执行的时候立马执行,用于最开始的初始化,监听ApplicationStartedEvent 事件)
(2)environmentPrepared(ApplicationContext创建之前,环境信准备之后执行一次,监听ApplicationEnvironmentPreparedEvent)
(3)contextPrepared(ApplicationContext创建之后,source加载之前调用一次)
(4)contextLoaded(ApplicationContext创建并加载之后,在refresh之前调用。监听ApplicationPreparedEvent)
(5)finished(run方法结束之前,监听ApplicationReadyEvent或ApplicationFailedEvent)
SpringApplicationRunListener 只有一个实现类就是刚才说的加载的EventPublishingRunListener。
**
* {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
* <p>
* Uses an internal {@link ApplicationEventMulticaster} for the events that are fired
* before the context is actually refreshed.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(context, exception);
if (context != null) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
}
private SpringApplicationEvent getFinishedEvent(
ConfigurableApplicationContext context, Throwable exception) {
if (exception != null) {
return new ApplicationFailedEvent(this.application, this.args, context,
exception);
}
return new ApplicationReadyEvent(this.application, this.args, context);
}
private static class LoggingErrorHandler implements ErrorHandler {
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
EventPublishingRunListener 看名字,事件发布执行监听器。看构造方法,SpringApplication ,参数,一个内部类SimpleApplicationEventMulticaster(应用事件多路广播器)。
过程:
SpringBootApplication run()执行时调用刚刚加载的EventPublishingRunListener中具体的方法(比如 starting()过程),EventPublishingRunListener 通过内部实现的事件广播器SimpleApplicationEventMulticaster将该过程(启动)封装成对应的事件(ApplicationStartedEvent)调用自己的方法multicastEvent 将改事件广播给之前对应的已经注册过的ApplicationListener 。ApplicationListener 拿到各种不同的事件消息进行各自的处理过程onApplicationEvent(E event)。
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}
}
继续看
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
创建应用的环境信息,如果是web 环境 获取StandardServletEnvironment 其他的获取StandardEnvironment
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);//发送ApplicationEnvironmentPreparedEvent 事件
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
创建spring 容器 context = createApplicationContext();
/**
* Strategy method used to create the {@link ApplicationContext}. By default this
* method will respect any explicitly set application context or application context
* class before falling back to a suitable default.
* @return the application context (not yet refreshed)
* @see #setApplicationContextClass(Class)
*/
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
//如果是web项目创建org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
//否则创建的是org.springframework.context.annotation.AnnotationConfigApplicationContex
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
接下来是
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//spring 容器创建之后的回调处理
postProcessApplicationContext(context);
//在 spring 容器刷新之前对注册过的 ApplicationContextInitializer 初始化
//实现 ApplicationContextInitializer的初始化器调用 void initialize(C applicationContext); 做相应额处理逻辑
applyInitializers(context);
//spring boot run 监听器 发送spring 容器创建消息
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
// 在容器refresh 前 spring boot run 监听器 发送 ApplicationPreparedEvent事件给相应的监听器执行
listeners.contextLoaded(context);
}
接下来 刷新容器
refreshContext(context);
afterRefresh(context, applicationArguments);
/**
* Called after the context has been refreshed.
* @param context the application context
* @param args the application arguments
*/
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
调用Spring容器中的ApplicationRunner和CommandLineRunner接口的实现类
/**
* Interface used to indicate that a bean should <em>run</em> when it is contained within
* a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
* within the same application context and can be ordered using the {@link Ordered}
* interface or {@link Order @Order} annotation.
*
* @author Phillip Webb
* @since 1.3.0
* @see CommandLineRunner
*/
public interface ApplicationRunner {
/**
* Callback used to run the bean.
* @param args incoming application arguments
* @throws Exception on error
*/
void run(ApplicationArguments args) throws Exception;
}
发送 finshed 至此容器初始化完成,各种监听器和初始化器也做了相应的工作。
listeners.finished(context, null);
run过程
1、找出所有的SpringApplicationRunListener并封装到SpringApplicationRunListeners中,用于监听run方法的执行(一共五个步骤)。监听的过程中会封装成对应的事件并通过内部实现的多路广播器广播出去让初始化过程中注册到应用程序中的监听器(springapplicationlistener)进行监听,做相应的操作。
2、构造Spring容器(ApplicationContext),并返回 创建Spring容器的判断是否是web环境,是的话构造AnnotationConfigEmbeddedWebApplicationContext,否则构造AnnotationConfigApplicationContext
初始化过程中产生的初始化器在这个时候开始工作
Spring容器的刷新(完成bean的解析、各种processor接口的执行、条件注解的解析等等)
3、从Spring容器中找出ApplicationRunner和CommandLineRunner接口的实现类并排序后依次执行