文章目录
- 谈谈你对Spring Boot的理解
- Spring Boot Starter有什么用
- Spring Boot的启动流程源码注释
- Spring Boot 约定优于配置
- Spring Boot自动装配原理
- Spring Boot自动装配过程
- 对Spring Boot注解的了解
- Spring Boot 的核心配置文件有哪几个?它们的区别是什么
- Spring Boot 的配置文件有哪几种格式?它们有什么区别?
- Spring Boot 配置加载顺序
- 什么是YAML,有什么优点。
- application.properties和bootstrap.properties有何区别
- Spring Boot中的监视器是什么
- Spring Boot可以兼容老Spring项目吗,如何做
- Spring Boot 2.X 有什么新特性?与1.X有什么区别?
- Spring Boot、Spring MVC 和 Spring 有什么区别?
- SpringBoot自动重装、热部署
序号 | 内容 |
---|---|
1 | 基础面试题 |
2 | JVM面试题 |
3 | 多线程面试题 |
4 | MySql面试题 |
5 | 集合容器面试题 |
6 | 设计模式面试题 |
7 | 分布式面试题 |
8 | Spring面试题 |
9 | SpringBoot面试题 |
10 | SpringCloud面试题 |
11 | Redis面试题 |
12 | RabbitMQ面试题 |
13 | ES面试题 |
14 | Nginx、Cancal |
15 | Mybatis面试题 |
16 | 消息队列面试题 |
17 | 网络面试题 |
18 | Linux、Kubenetes面试题 |
19 | Netty面试题 |
谈谈你对Spring Boot的理解
SpringBoot主要用来简化使用Spring的难度和繁重的XML配置,它是Spring组件的一站式解决方案,采取了习惯优于配置的方法。通过.properties或者.yml文件替代了Spring繁杂的XML配置文件,同时支持@ImportResource注解加载XML配置。Spring Boot还提供了嵌入式HTTP服务器、命令行接口工具、多种插件等等,使得应用程序的测试和开发简单起来。
1、可以快速构建项目;
2、可以对主流开发框架的无配置集成;
3、项目可独立运行,无需外部依赖Servlet容器;
4、提供运行时的应用监控;
5、可以极大地提高开发、部署效率;
缺点:
1、集成度很高,对于了解底层不容易。
2、将原有的spring项目转成springboot项目,很困难,更适合新建的项目。
3、版本迭代速度很快,一些模块改动很大。
4、缺乏控制。spring boot 会创建大量未使用的依赖项,导致部署文件很大
Spring Boot Starter有什么用
Spring Boot通过提供众多起步依赖(Starter)降低项目依赖的复杂度。起步依赖本质上是一个Maven项目对象模型(Project Object Model, POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。很多起步依赖的命名都暗示了它们提供的某种或某类功能。
举例来说,你打算把这个阅读列表应用程序做成一个Web应用程序。与其向项目的构建文件里添加一堆单独的库依赖,还不如声明这是一个Web应用程序来得简单。你只要添加Spring Boot的Web起步依赖就好了。
常用的starter :
spring-boot-starter-web嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa数据库支持
spring-boot-starter-data-redis redis数据库支持
spring-boot-starter-data-solr solr支持
mybatis-spring-boot-starter第三方的mybatis集成starter
Spring Boot的启动流程源码注释
spring boot 启动可以分为两步,初始化一个SpringApplication对象,第二步,执行该对象的run方法。new SpringApplication().run();
public static void main(String[] args) {
SpringApplication.run(AssetApplication.class, args);
}
//main方法调用这个run方法。
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
//上面的run方法调用这个run方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
第一步
初始化一个SpringApplication对象,就是调用new SpringApplication() 。启动类的run方法是调用的SpringApplication的两个参数的构造方法创建了SpringApplication对象
SpringApplication构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//资源加载器
this.resourceLoader = resourceLoader;
//断言判断primarySources不为空
Assert.notNull(primarySources, "PrimarySources must not be null");
//主要资源,就是启动类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//应用程序类型,(SERVLET,REACTIVE,NONE)默认是SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置初始化。将返回的实例对象()放入到新建的集合list中。一共7个
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器。将返回的实例对象放入到新建的集合list中。一共11个
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推导出主应用程序是哪个类。新建一个运行时异常对象,通过这个对象获取当前调用函数堆栈StackTrace,然后遍历这个数组,找到方法名为main的类
this.mainApplicationClass = deduceMainApplicationClass();
}
//设置初始化和监听调用的方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {、
//获取当前类的类加载器,当前的类在spring-boot.jar包下面
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates(使用名称并确保唯一,以防止重复)
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//根据每个name通过反射找到对应实例,将实例放到集合list 中
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
//返回找到的实例对象 list。
return instances;
}
//SpringFactoriesLoader.loadFactoryNames方法。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories 方法通过当前类加载器从classPath下获取所有的jar包,再去找jar包下的"META-INF/spring.factories"文件,从配置文件中获取到ApplicationContextInitializer相关的配置(全限定名类),返回一个map,通过getOrDefault转为一个list。
第二步
new SpringApplication().run();调用SpringApplication对象的run方法。
Springapplication run方法的流程:
1、获取SpringapplicationListener监听器;
2、启动所获取到的所有监听器;
3、初始化ConfigurableEnvironment(配置文件);
4、打印Banner图标(启动时控制台显示的SPRING图标);
5、创建请求上下文
6、获取spring.factories配置文件中的key为SpringBootExceptionReporter的实例化对象,并放入到集合中
7、向上下文对象中设置一系列属性值。
8、调用AbstractApplicationContext 的refresh 方法 创建IOC容器,并将bean注册到容器中,以及对bean的处理。
9、监听器通知容器正在运行;
//设置启动时间,StopWatch计时对象
StopWatch stopWatch = new StopWatch();
//计时开始
stopWatch.start();
//计时结束
stopWatch.stop();
//下面会用到这个对象
ConfigurableApplicationContext context = null;
//定义一个异常集合,用来存放异常。
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//向系统中设置headless属性。
configureHeadlessProperty();
1、获取SpringapplicationListener监听器;
SpringApplicationRunListeners listeners = getRunListeners(args);
//getSpringFactoriesInstances 从spring.factories文件中加载key是SpringApplicationRunListener相关的类。
//SpringApplicationRunListener在spring.factories文件中对应的是org.springframework.boot.context.event.EventPublishingRunListener类。
//EventPublishingRunListener类的作用是(@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.)
//当前运行这个SpringApplicationRunListener用来发布一些事件。EventPublishingRunListener是SpringApplicationRunListener的子类
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
2、启动所获取到的所有监听器;
listeners.starting();
//this.listeners = EventPublishingRunListener.
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
//listener.starting(); 调用EventPublishingRunListener类的starting方法
@Override
public void starting() {
//initialMulticaster 广播器,创建一个ApplicationStartingEvent(启动)事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
//将args参数包装成ApplicationArguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
3、初始化ConfigurableEnvironment(配置文件);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
//忽略掉配置了spring.beaninfo.ignore属性的对象。
configureIgnoreBeanInfo(environment);
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
4、打印Banner图标(启动时控制台显示的SPRING图标);
Banner printedBanner = printBanner(environment);
5、创建请求上下文
context = createApplicationContext();
//在创建SpringApplication对象时设置了webApplicationType,默认是SERVLET。
//DEFAULT_SERVLET_WEB_CONTEXT_CLASS = //org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
//通过反射获取到对象AnnotationConfigServletWebServerApplicationContext。
//通过BeanUtils.instantiateClass实例化一个ConfigurableApplicationContext对象
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
//实例化一个ConfigurableApplicationContext对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
6、获取spring.factories配置文件中的key为SpringBootExceptionReporter的实例化对象,并放入到集合中
//Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();上面定义的集合
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
7、向上下文对象中设置一系列属性值。
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//上下文设置环境。
context.setEnvironment(environment);
//设置程序的转化器和格式化程序
//context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
postProcessApplicationContext(context);
//使用ApplicationContextInitializer初始化器对上下文进行初始化
applyInitializers(context);
//listeners = EventPublishingRunListener,监听器发布ApplicationContextInitializedEvent事件
/*
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
*/
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//getBeanFactory 获取到的工厂是 DefaultListableBeanFactory,
//DefaultListableBeanFactory继承了 ConfigurableListableBeanFactory 接口
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册单例springApplicationArguments对象。
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//判断printedBanner是否为空,不为空则注册一个springBootBanner对象
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//判断beanFactory是否为DefaultListableBeanFactory
//setAllowBeanDefinitionOverriding(设置是否允许通过注册具有相同名称的不同定义来覆盖 bean 定义,自动替换前者,默认为true。)
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//private boolean lazyInitialization = false;
//lazyInitialization(是否是懒加载) 默认为false,
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
/*protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}*/
// loader.load(); 调用load()方法
/*int load() {
int count = 0;
for (Object source : this.sources) {
count += load(source);
}
return count;
}*/
//load(source); 调用 load((Class<?>) source)方法
/*private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}*/
//isComponent 判断source(资源类SpringBootApplication)是否包好@Component注解,如果包含则调用this.annotatedReader.register(source);
//AnnotatedBeanDefinitionReader annotatedReader通过注解的方式可以被扫描到,并将beanDefinition注册到BeanDefinitionRegistry中。
//registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
/*private int load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}*/
//监听器广播ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
8、调用AbstractApplicationContext 的refresh 方法 创建IOC容器,并将bean注册到容器中,以及对bean的处理。
refreshContext(context);
9、监听器通知容器正在运行;
//再一次刷新上下文,是空方法,可能是为了后续扩展。
afterRefresh(context, applicationArguments);
//记录结束时间
stopWatch.stop();
//打印日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//使用广播和回调机制通知监听器SpringBoot容器启动成功
listeners.started(context);
//遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法
//我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展
callRunners(context, applicationArguments);
try {
//使用广播和回调机制通知监听器SpringBoot容器启动成功并运行中
listeners.running(context);
}
Spring Boot 约定优于配置
- 约定优于配置是一种软件设计的范式,他的核心思想是减少开发人员对于配置项的维护,从而让开发人员更加聚焦于业务逻辑上,
- spring Boot 是约定优于配置的产物,它类似于spring框架下的一个脚手架。通过spring boot 我们可以快速开发基于spring生态下的应用程序
- 基于传统的spring框架,开发web应用的时候,我们需要做很多和业务无关的并且只需要做一次的配置项。例如管理jar包的依赖、web.xml的维护、应用需要自己手动部署到web容器、第三方组件集成到spring IOC的时候我们需要做配置项的维护。在spring boot 中我们不在需要这些繁琐的配置,因为spring boot 已经帮我们自动完成了。完成这些动作的前提,就是基于约定优于配置这样的思想
- spring boot 约定优于配置的体现有很多。例如:
- spring boot start 启动依赖,它能够帮助我们管理所有的jar包版本。
- 如果当前的应用依赖了web这样一个jar包,那么spring boot 会自动内置tomcat 容器来运行web应用我们不在需要单独应用部署
- springboot 自动装配机制的实现中,通过扫描约定路径下的springFactoriesLoader文件,去进行识别配置类,从而实现Bean的自动装载。
- spring boot 会默认加载resource目录下的application.properties文件。
约定优于配置是一个比较常见的软件设计思想,它的核心本质都是为了去更加高效以及便捷的去实现软件系统的开发和维护。
Spring Boot自动装配原理
自动装配就是自动去把第三方组件的bean装载到IOC容器中,不需要开发人员再去写相关的配置。在spring boot应用中,只需要在启动类加上@SpringBootApplication注解,就可以实现自动装配。@SpringBootApplication注解是一个复合注解,主要是由@SpringBootConfiguraton、@EnableAutoConfiguration、@ComponentScan三个注解构成。@EnableAutoConfiguration开启了自动配置。自动装配的实现主要依靠三个核心技术。
第一个:引入starter启动依赖组件的时候,这个组件中必须包含@Configuration配置类,在这个配置类中,我们需要通过@Bean这个注解去声明需要装配到IOC容器中的bean对象。
第二个:这个配置类是放在第三方的jar包中。然后通过springBoot中的约定优于配置的理念,去把这个类的全路径放在classpath:/META-INF/spring.factories文件中,这样springBoot就可以知道第三方jar包里面这个配置类的位置。这个步骤主要是用到了spring中的springFactoriesLoader来完成的。
第三个:springBoot拿到所有第三方jar包里面声明的配置类后,再通过spring提供的ImportSelector这样的一个接口来实现对这些类的动态加载,从而完成自动装配这样一个动作。
springBoot 是约定优于配置的产物,在很多地方都会看到这样的思想。它的出现可以让开发人员更加的专注于业务开发,而不需要关心和业务无关的配置。
@EnableAutoConfiguration 由两个注解构成@AutoConfigurationPackage、@Import(AutoConfigurationImportSelector.class)。
@AutoConfigurationPackage:作用是将主配置类所在包以及子包里面的所有组件扫描并加载到spring容器中。
@Import(AutoConfigurationImportSelector.class):作用是将需要自动装配的类以全限定名的方式返回。主要是通过调用AutoConfigurationImportSelector的**selectImports()**方法。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//返回需要自动装配的类。
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取注解类@EnableAutoConfiguration的exclude和excludeName属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//获取需要自动装配的类的全限定名。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//getSpringFactoriesLoaderFactoryClass 方法返回的 EnableAutoConfiguration.class。开启自动配置的注解。
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
//SpringFactoriesLoader.loadFactoryNames方法。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
//loadSpringFactories 方法通过当前类加载器从classPath下获取所有的jar包,再去找jar包下的"META-INF/spring.factories"文件,从配置文件中获取到EnableAutoConfiguration相关的配置(全限定名类),返回一个map,通过getOrDefault转为一个list。
//通过HashSet移除重复的类全限定名
configurations = removeDuplicates(configurations);
//获取被排除类的集合。
//它会收集@EnableAutoConfiguration注解中配置的exclude属性值excludeName属性值并通过方法getExcludeAutoConfigurationsProperty获取在配置文件中key为spring.autoconfigure.exclude的配置值。以排除自动配置。例如:spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSource-AutoConfiguration
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检验configurations中需要排除的内容
checkExcludedClasses(configurations, exclusions);
// 移除configurations中需要排除的内容
configurations.removeAll(exclusions);
// 再次对configurations中的内容进行过滤,将不生效的自动配置剔除出去。
configurations = getConfigurationClassFilter().filter(configurations);
// 关闭spring监听器中的自动装配事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
Spring Boot自动装配过程
1、当启动SpringBoot应用程序的时候,会先创建SpringApplication对象,在构造方法中会进行一些参数的初始化工作,比如会加载Spring.factories文件,将文件的内容放到缓存对象中,方便后续获取
2、SpringApplication对象创建完成后,开始调用run方法,启动过程中最主要有两个方法,第一个叫prepareContext(),第二个叫refreshContext()方法
3、在prepareContext()方法主要是对上下文对象ConfigurableApplicationContext的初始化操作,在整个过程中有个非常重要的方法就是load()方法,它会将当前启动类作为一个BeanDefinition注册到BeanDefinitionMap中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的启动类,来完成对应注解的解析工作
4、在refreshContext()方法会进行整个Spring容器的刷新refresh操作,会调用spring的refresh()方法,自动装配过程是在invokeBeanFactoryPostProcessor方法()中进行(也就是执行BeanFactory的后置处理器),在此方法主要是针对ConfigurationClassPostProcessor类的处理
5、在执行BeanFactory后置处理器的时候会调用ConfigurationClassPostProcessor类中的parse()方法去解析处理各种注解比如@CompomentScan、@Import等等
6、在解析@Import注解的时候比较特别,会有一个collectImports()方法,从主类开始递归解析注解,把所有包含@Import的注解都解析到BeanDefinitionMap中
7、调用AutoConfigurationImportSelector类(相当于一个处理器)中的process()方法进而触发getCandidateConfigurations()方法获取Spring.factories文件下的key为EnableAutoConfiguration的所有value
对Spring Boot注解的了解
1、@SpringBootapplication注解:
在Spring Boot入口类中,唯一的一个注解就是@SpringBootapplication。它是Spring Boot项目的核心注解,用于开启自动配置,准确说是通过该注解内组合的@EnableAutoConfiguration开启了自动配置。
2、@EnableAutoConfiguration注解:
允许 Spring Boot 自动配置注解,开启这个注解之后,Spring Boot 就能根据当前类路径下的包或者类来配置 Spring Bean。
3、@Conditional注解:
@Conditional注解是由Spring 4.0版本引入的新特性,可根据是否满足指定的条件来决定是否进行Bean的实例化及装配。
Spring Boot 的核心配置文件有哪几个?它们的区别是什么
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件主要用于 Spring Boot 项目的自动化配置。 bootstrap 配置文件有三个应用场景。 使用Spring Cloud Config配置中心时,需要在 bootstrap 配置文件中添加连接到配置中心的配置属性,来加载外部配置中心的配置信息; 一些固定的不能被覆盖的属性; 一些加密或解密的场景;
Spring Boot 的配置文件有哪几种格式?它们有什么区别?
主要有.properties 和 .yml格式,它们的区别主要是书写格式不同。另外,.yml 格式不支持 @PropertySource 注解导入配置。
Spring Boot 配置加载顺序
Spring Boot配置加载顺序优先级是:propertiese文件、YAML文件、系统环境变量、命令行参数。
什么是YAML,有什么优点。
YAML 是一种可读的数据序列化语言,它通常用于配置文件。
优点:配置有序 、 支持数组,数组中的元素可以是基本数据类型或者对象、 简洁方便
application.properties和bootstrap.properties有何区别
bootstrap比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效, 而且boostrap 里面的属性不能被覆盖; application用于 spring boot 项目的自动化配置。
Spring Boot中的监视器是什么
Spring Boot Actuator可以帮助你监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等。所有的这些特性可以通过JMX或者HTTP endpoints来获得。
Actuator同时还可以与外部应用监控系统整合,比如Prometheus , Graphite , DataDog , Influx , Wavefront , New Relic等。
这些系统提供了非常好的仪表盘、图标、分析和告警等功能,使得你可以通过统一的接口轻松的监控和管理你的应用。
Actuator 使用 Micrometer 来整合上面提到的外部应用监控系统。这使得只要通过非常小的配置就可以集成任何应用监控系统。
将Spring Boot Actuator集成到一个项目中非常简单。我们需要做的就是在pom.xml文件中包含spring-boot-starter-actuator启动器:
Spring Boot可以兼容老Spring项目吗,如何做
可以兼容,使用@ImportResource注解导入老Spring项目配置文件。
Spring Boot 2.X 有什么新特性?与1.X有什么区别?
- 配置变更:在2.x 中废除了一些1.x 中的配置,并增加了许多新配置
- 依赖JDK版本升级:2.x至少需要JDK 8 的支持,2.x里面的许多方法应用了JDK 8的许多高级新特性,所以你要升级到2.0 版本,先确认你的应用必须兼容JDK 8。另外,2.x开始了对JDK 9的支持。
- 第三方类库升级:2.x 对第三方类库升级了所有能升级的稳定版本。例如:Spring Framework 5+,Tomcat 8.5+
- 配置属性绑定:在2.x中,配置绑定功能有了些的改造,在调整了1.x中许多不一致地方之外,还提供了独立于注解之外的API来装配配置属性。并增加了属性来源,这样你就能知道这些属性是从哪个配置文件中加载进来的。
Spring Boot、Spring MVC 和 Spring 有什么区别?
Spring包含了SpringMVC,而SpringBoot又包含了Spring或者说是在Spring的基础上做得一个扩展。Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便。
spring
Spring是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就是控制反转(IOC),和面向切面(AOP),简单的说就是一个分层的轻量级开源框架。
Spring MVC
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。SpringMVC是一种web层mvc框架,用于替代servlet(处理|响应请求,获取表单参数,表单校验等。SpringMVC是一个MVC的开源框架,SpringMVC=struts2+spring,springMVC就相当于是Struts2加上Spring的整合。
SpringBoot
Springboot是一个微服务框架,延续了spring框架的核心思想IOC和AOP,简化了应用的开发和部署。Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题—>习惯大于约定。
SpringBoot自动重装、热部署
pom.xml中添加spring-boot-devtools 的maven依赖