赞
踩
spring能干什么
Spring Boot2
Spring Boot能干什么
Spring Boot 特性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zskjxyun-1629195611467)(/Users/apple/Library/Application Support/typora-user-images/image-20210802173621401.png)]
ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class, args);
//打印上下文的所有的bean
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gAitteaQ-1629195611468)(/Users/apple/Library/Application Support/typora-user-images/image-20210802173908825.png)]
(scanBasePackages = “com.fan”):扫描包
run方法
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPH8HxpQ-1629195611470)(/Users/apple/Library/Application Support/typora-user-images/image-20210802174308779.png)]
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration
作用:表示该注解标注的类是一个配置类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan
作用:表示有一个组件扫描的作用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bq7Uk2sS-1629195611472)(/Users/apple/Library/Application Support/typora-user-images/image-20210802194538781.png)]
作用:对应的是扫描路径:new PackageImports(metadata).getPackageNames() = com.muse.springbootdemo
自动注入选择器
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
SpringFactoriesLoader类
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { Enumeration urls = classLoader.getResources("META-INF/spring.factories"); 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 factoryTypeName = ((String)entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for(int var12 = 0; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } }
加载原理
import是全路径名加载到ioc容器中
@Import({Soldier.class, Gun.class})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dG5Ncmpn-1629195611472)(/Users/apple/Library/Application Support/typora-user-images/image-20210802192234328.png)]
@ConfigurationProperties(prefix = "muse")//前缀muse
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCsuhQ38-1629195611473)(/Users/apple/Library/Application Support/typora-user-images/image-20210802193112102.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v2usj3WH-1629195611475)(/Users/apple/Library/Application Support/typora-user-images/image-20210802193154904.png)]
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
// eg1: primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class} args={}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
创建SpringApplication
SpringApplication springApplication = new SpringApplication(primarySources);
七个步骤,全是初始化属性
// eg1: resourceLoader=null primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class} @SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // eg1: resourceLoader=null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // eg1: primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class} this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // eg1: webApplicationType=WebApplicationType.SERVLET this.webApplicationType = WebApplicationType.deduceFromClasspath(); // eg1: bootstrapRegistryInitializers=new ArrayList<>(); this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); // eg1: initializers=7个ApplicationContextInitializer的实现类 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // eg1: listeners=8个ApplicationListener的实现类 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // eg1: mainApplicationClass=com.muse.springbootdemo.SpringbootDemoApplication.class this.mainApplicationClass = deduceMainApplicationClass(); }
初始化resourceLoader(资源加载器)
resourceLoader=null
- 1
初始化Set<Class<?>> primarySources;(主要的资源类集合)
primarySources=Class[]{com.muse.springbootdemo.SpringbootDemoApplication.class}
- 1
初始化WebApplicationType webApplicationType(web应用类型 3 种)
通过classpath判断我们现在正在使用的是哪一种web应用类型?
// eg1: 以开启spring mvc为例 static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) // eg1: 找不到org.springframework.web.reactive.DispatcherHandler类,则第一个判断返回false && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } // eg1: SERVLET_INDICATOR_CLASSES={"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"} for (String className : SERVLET_INDICATOR_CLASSES) { // eg1: Servlet和ConfigurableWebApplicationContext都是存在的,所以都返回true if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } // eg1: return WebApplicationType.SERVLET; return WebApplicationType.SERVLET; }
webApplicationType=WebApplicationType.SERVLET /** * The application should not run as a web application and should not start an * embedded web server. * 不是web应用 */ NONE, /** * The application should run as a servlet-based web application and should start an * embedded servlet web server. * MVC */ SERVLET, /** * The application should run as a reactive web application and should start an * embedded reactive web server. * 响应式编程 */ REACTIVE;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
初始化List bootstrapRegistryInitializers (引导程序注册的初始化)
从MEAT-INF/spring.factories配置文件中,获取BootStrapper.class和BootStrapRegistryInitaializer.class这两个配置类型,然后合并存储到bootstraoRegistryInitializers中。
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
// eg1: getSpringFactoriesInstances(Bootstrapper.class)返回空的List,
// 说明Bootstrapper在spring.factories的配置文件中也没有配置,所以lambda表达式对返回值什么都没处理
getSpringFactoriesInstances(Bootstrapper.class).stream().map((bootstrapper) ->
((BootstrapRegistryInitializer) bootstrapper::initialize)).forEach(initializers::add);
// eg1: getSpringFactoriesInstances(BootstrapRegistryInitializer.class) 返回空的List
// 说明BootstrapRegistryInitializer在spring.factories的配置文件中也没有配置
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// eg1: 返回new ArrayList<>();
return initializers;
}
bootstrapRegistryInitializers=new ArrayList<>();
- 1
getSpringFactoriesInstances
BootStrapper.class和BootStrapRegistryInitaializer.class都通过上面的方式初始化
ApplicationContextInitializer.class 和 ApplicationListener.class都通过上面的方式初始化
初始化 List<ApplicationContextInitializer<?>> initializers(应用上下文的初始化)
初始化 List<ApplicationListener<?>> listeners(监听器的初始化)
初始化 Class<?> mainApplicationClass(主应用类)
private Class<?> deduceMainApplicationClass() { try { /** 通过new RuntimeException().getStackTrace()获得调用栈轨迹的数组 */ // eg1: stackTrace.size()= 6 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { // eg1: stackTraceElement.getClassName()=com.muse.springbootdemo.SpringbootDemoApplication return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
Class<?> mainApplicationClass = com.muse.springbootdemo.SpringbootDemoApplication.class
SpringFactoriesLoader
// eg1: classLoader=ClassLoaders$AppClassLoader@1967 /** * 处理流程: * 1> 读取所有依赖jar包中,每一个存在META-INF/spring.factories的配置文件内容; * 2> 将配置文件中的内容维护到Map<String, List<String>> result中,如果key相同,则value取合集; * 3> 将result维护到缓冲cache中——key=ClassLoader value=result * 4> 将result作为返回值返回。 */ private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { // eg1: cache.size()=0 Map<String, List<String>> result = cache.get(classLoader); // eg1: result=null if (result != null) { return result; } result = new HashMap<>(); try { // eg1: FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); while (urls.hasMoreElements()) { // eg1-1: jar:file:/Users/muse/.m2/repository/org/springframework/boot/spring-boot/2.5.1/spring-boot-2.5.1.jar!/META-INF/spring.factories // eg1-2: jar:file:/Users/muse/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.1/spring-boot-autoconfigure-2.5.1.jar!/META-INF/spring.factories // eg1-3: jar:file:/Users/muse/.m2/repository/org/springframework/spring-beans/5.3.8/spring-beans-5.3.8.jar!/META-INF/spring.factories URL url = urls.nextElement(); // eg1-1: 通过url获得资源resource,并将spring-boot-2.5.1.jar包下spring.factories文件中的配置信息,加载到properties中。共计13个配置项 // eg1-2: 通过url获得资源resource,并将spring-boot-autoconfigure-2.5.1.jar包下spring.factories文件中的配置信息,加载到properties中。共计9个配置项 // eg1-3: 通过url获得资源resource,并将spring-beans-5.3.8.jar包下spring.factories文件中的配置信息,加载到properties中。共计1个配置项 UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); // eg1-1:【仅以第一次循环为例】 for (Map.Entry<?, ?> entry : properties.entrySet()) { // eg1-1-1: factoryTypeName="org.springframework.boot.diagnostics.FailureAnalysisReporter" String factoryTypeName = ((String) entry.getKey()).trim(); // eg1-1-1: factoryImplementationNames=String[]{"org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter"} String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { // eg1: result key="org.springframework.boot.diagnostics.FailureAnalysisReporter" // value={"org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter"} /** * result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()): * * 如果<Map>result中不存在指定的key=factoryTypeName,则创建并将value赋值为new ArrayList<>(),再将value值返回。 * * 如果存在指定的key,则直接将value作为返回值。 */ result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()).add(factoryImplementationName.trim()); } } } /** * Replace all lists with unmodifiable lists containing unique elements * * collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)方法的使用: * * 先进行结果集的收集,然后将收集到的结果集进行下一步的处理;即:就是把第一个参数downstream的结果,交给第二个参数Function * * 函数的参数里面,R apply(T t),也就是将结果设置成t。 */ // eg1: 将value中的ArrayList类型,由UnmodifiableRandomAccessList封装一层。 result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); /** * 为什么result.size()的最终大小为18个配置项? * --------------------------------------------------------------------------------------------- * 【spring-boot-2.5.1.jar】 配置项key:共13个 * org.springframework.boot.logging.LoggingSystemFactory * org.springframework.boot.env.PropertySourceLoader * org.springframework.boot.context.config.ConfigDataLocationResolver * org.springframework.boot.context.config.ConfigDataLoader * org.springframework.boot.SpringApplicationRunListener * org.springframework.boot.SpringBootExceptionReporter * org.springframework.context.ApplicationContextInitializer * org.springframework.context.ApplicationListener * org.springframework.boot.env.EnvironmentPostProcessor * org.springframework.boot.diagnostics.FailureAnalyzer * org.springframework.boot.diagnostics.FailureAnalysisReporter * org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector * org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector *--------------------------------------------------------------------------------------------- * 【spring-boot-autoconfigure-2.5.1.jar】 配置项key:共9个,重复5个 * (重复)org.springframework.context.ApplicationContextInitializer * (重复)org.springframework.context.ApplicationListener * (重复)org.springframework.boot.env.EnvironmentPostProcessor * org.springframework.boot.autoconfigure.AutoConfigurationImportListener * org.springframework.boot.autoconfigure.AutoConfigurationImportFilter * org.springframework.boot.autoconfigure.EnableAutoConfiguration * (重复)org.springframework.boot.diagnostics.FailureAnalyzer * org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider * (重复)org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector *--------------------------------------------------------------------------------------------- * 【spring-beans-5.3.8.jar】 配置项key:共1个 * org.springframework.beans.BeanInfoFactory * * 【总计配置项key】13 + 4 + 1 = 18个 */ // eg1: classLoader=ClassLoaders$AppClassLoader@1967 result.size()=18 cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } // eg1: result.size()=18 return result; }
调用SpringApplication实例去运行(run)
springApplication.run(args)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。