当前位置: 首页 > news >正文

威海市建设局官方网站外国网站的风格

威海市建设局官方网站,外国网站的风格,wordpress 添加水印,免费做名片的网站SpringBoot原理分析 作为一个javaer#xff0c;和boot打交道是很常见的吧。熟悉boot的人都会知道#xff0c;启动一个springboot应用#xff0c;就是用鼠标点一下启动main方法#xff0c;然后等着就行了。我们来看看这个main里面。 SpringBootApplication public class E…SpringBoot原理分析 作为一个javaer和boot打交道是很常见的吧。熟悉boot的人都会知道启动一个springboot应用就是用鼠标点一下启动main方法然后等着就行了。我们来看看这个main里面。 SpringBootApplication public class ExampleApplication {public static void main(String[] args) {SpringApplication.run(ExampleApplication.class, args);} }这个类很简单吧有三个注意点。 ExampleApplication就是类名为了规范起见这个类名一般都是xxxApplication。 有一个注解SpringBootApplication。 然后就一个main方法里面使用了SpringApplication的静态方法run()传进去了俩参数。 这就神奇地启动起来了为什么呢 分析的版本SpringBoot 2.7.18 需要结合以前用xml文件来配置Spring容器的形式来对比Boot用注解的形式 1.注解自动配置 目前只知道注解的作用即可至于这些注解是怎么起作用的见后续… SpringBootApplication 这一节来详细聊一聊这个注解。SpringBootApplication 是 Spring Boot 框架中的一个核心注解用于简化 Spring Boot 应用的配置和启动 它的作用 SpringBootApplication 标注在应用的主类上用于启动 Spring Boot 应用。它启用了 Spring Boot 的自动配置机制根据项目的依赖自动配置 Spring 应用。组件扫描它启用了组件扫描自动发现并注册带有 Component、Service、Repository、Controller 等注解的类。配置类它标记该类为 Spring 的配置类相当于 Configuration 注解。 点进去看看该注解的结构如下 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited // 四个元注解 SpringBootConfiguration EnableAutoConfiguration //启用SpringBoot的自动配置机制。SpringBoot会根据类路径中的依赖自动配置应用。例如如果类路径中有spring-boot-starter-webSpringBoot会自动配置Tomcat和SpringMVC。ComponentScan(excludeFilters { Filter(type FilterType.CUSTOM, classes TypeExcludeFilter.class),Filter(type FilterType.CUSTOM, classes AutoConfigurationExcludeFilter.class) }) // 启用组件扫描并排除一些特定的过滤器。默认是注解标注的类所在包及其子包。实际上是不是就是主启动类所在包及其子包 public interface SpringBootApplication { .............. }// 发现这是一个组合注解SpringBootConfiguration 注解主要作用是标记一个类为 Spring Boot 的配置类与 Configuration 类似但它专门用于 Spring Boot 应用。这个注解和ComponentScan注解结合到一起达成了如下效果。左边是xml文件配置形式右边是SpringBoot注解的形式这俩注解在一起就是扫描主启动类所在包及其子包下的被Controller、Service、…标注的类将他们归到Spring容器里面去。 EnableAutoConfiguration EnableAutoConfiguration注解 这个注解不得了啊。 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited AutoConfigurationPackage Import(AutoConfigurationImportSelector.class) // 这里。 public interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration;Class?[] exclude() default {};String[] excludeName() default {};}发现Import注解。这个注解的作用是干啥的这里给出GPT的回答Import 是 Spring 框架提供的一个注解用于将一个或多个配置类Configuration 类或组件类导入到当前的 Spring 应用上下文中。它可以用来显式地引入其他配置类或 Bean 定义从而实现模块化配置和代码复用。 这里有一个非常重要的东西那就是当前的Spring上下文也就是主启动类所在包及其子包Import(AutoConfigurationImportSelector.class)这句话的意思是将SpringBoot官方写的AutoConfigurationImportSelector类导入到当前Spring上下文中在当前Spring上下文注册这样一个bean。 AutoConfigurationImportSelector探究 public interface ImportSelector {String[] selectImports(AnnotationMetadata importingClassMetadata); } // 实现了DeferredImportSelector接口DeferredImportSelector实现了ImportSelector public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {...........AutoConfigurationEntry autoConfigurationEntry getAutoConfigurationEntry(annotationMetadata); // 1.进去return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}// 2.这个方法protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes getAttributes(annotationMetadata);// 3.进入这里ListString configurations getCandidateConfigurations(annotationMetadata, attributes);...........}// 4. 3调用的这个方法protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {ListString configurations new ArrayList(// 5. 继续往下SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations,No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.);return configurations;}// 6. 5处调用的方法public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) {...... // loadSpringFactoriesreturn loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}// 7// 最终可以在loadSpringFactories方法里面看到这样一行代码//EnumerationURL urls classLoader.getResources(FACTORIES_RESOURCE_LOCATION);// public static final String FACTORIES_RESOURCE_LOCATION META-INF/spring.factories;// 结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。 }结合idea打断点调试我们发现getCandidateConfigurations扫描到了引入的所有jar包的META-INF/spring.factories共有156个xxxAutoConfigure类。但是这些都会用到吗别忘了SpringBoot有个非常强大的特点那就是导入场景、对应的场景才会生效 继续往下走请看下图发现只有50个了例如上图里面的amqp由于项目中没有用到故在这里就没有了经过了filter过滤 以RabbitMq自动配置为例 AutoConfiguration ConditionalOnClass({ RabbitTemplate.class, Channel.class }) // 这两个类存在时才生效项目里面没导入相关jar包故RabbitAutoConfiguration不会被导入Spring容器生效下面就来说这个注解 EnableConfigurationProperties(RabbitProperties.class) Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class }) public class RabbitAutoConfiguration {................ }ConditionalOnClass 先看看其源码 Target({ ElementType.TYPE, ElementType.METHOD }) Retention(RetentionPolicy.RUNTIME) Documented Conditional(OnClassCondition.class) // 这里*** public interface ConditionalOnClass {Class?[] value() default {};String[] name() default {}; }ConditionalOnClass注解的作用是当项目中存在某个类时才会使标有该注解的类或方法生效 先看我们的主类**【1. 此时没有引入test.demo.test.list.Student所在的maven依赖】** /* 下面是这俩类 public class Cat {private Integer id;private String name; } public class Dog {private Integer id;private String name; }*/SpringBootApplication MapperScan(com.feng.tackle.dao) public class DateApplication {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(DateApplication.class, args);ConfigurableListableBeanFactory beanFactory context.getBeanFactory();IteratorString iterator beanFactory.getBeanNamesIterator();while (iterator.hasNext()) {String name iterator.next();if ( name.equals(dog01) || name.equals(cat01) ) System.out.println(name); // 看看有没有这两个名字的bean}} } // 最后的输出结果 /* cat01 */在配置类中我们这样做 Configuration public class ConditionTestConfig {ConditionalOnClass(name test.demo.test.list.Student) // 类路径有这个类就往容器中放入该beanBeanpublic Dog dog01() {return new Dog(2, 汪汪汪);}ConditionalOnMissingClass(test.demo.test.list.Student) // 类路径没有这个类就往容器中放入该beanBeanpublic Cat cat01() {return new Cat(1, 喵喵喵);} }main最后的输出结果是cat01。test.demo.test.list.Student是另一个maven项目里面的类。 【2. 项目中引入Student所在的maven】 dependencygroupIdcom.feng.test/groupIdartifactIdtest-demo/artifactIdversion1.0-SNAPSHOT/version /dependency再次启动main输出结果dog01 通过这个例子我们可以知道SpringBoot自动配置导入具体starter对应的场景才会生效。【由于没有导入MQ的starter故此配置类不会生效】 总结 **自动配置 ** 以spring-boot-starter-web为例子引入该启动器他的父级pom里面有spring-boot-starterspring-boot-starter的父级pom有spring-boot-autoconfigure。 spring-boot-autoconfigure里面有Spring官方定义的所有场景。 EnableAutoConfiguration 注解这是自动配置的入口通常由 SpringBootApplication 注解组合引入。spring.factories 文件Spring Boot 通过 META-INF/spring.factories 文件加载自动配置类。条件化配置通过 Conditional 系列注解如 ConditionalOnClass、ConditionalOnMissingBean 等实现按需加载配置。 自动配置的流程 加载自动配置类 SpringBootApplication 注解该注解是一个组合注解包含了 EnableAutoConfiguration用于启用自动配置。EnableAutoConfiguration 的作用该注解会通过 SpringFactoriesLoader 加载 META-INF/spring.factories 文件中定义的自动配置类。 条件化配置 自动配置类通常使用 Conditional 系列注解来控制是否生效 Configuration(proxyBeanMethods false) ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) ConditionalOnMissingBean(type io.r2dbc.spi.ConnectionFactory) EnableConfigurationProperties(DataSourceProperties.class) Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class }) public class DataSourceAutoConfiguration {// 自动配置逻辑 } //如果类路径中存在 DataSource 和 EmbeddedDatabaseType且容器中没有 ConnectionFactory Bean则自动配置 DataSource。加载配置属性 EnableConfigurationProperties自动配置类通常会通过该注解加载配置属性。application.properties 或 application.ymlSpring Boot 会读取这些配置文件中的属性并将其绑定到对应的配置类中。 ConfigurationProperties(prefix spring.datasource) public class DataSourceProperties {private String url;private String username;private String password;// getters and setters }注册bean 自动配置类通过 Bean 方法向容器中注册 Bean。这些 Bean 通常是框架的核心组件如 DataSource、DispatcherServlet、SecurityFilterChain 等。 2. 启动过程 SpringApplication.run(ExampleApplication.class, args);这一行代码做了啥这才是重点 从run开始看一层一层往下面点进去 // 1. public static ConfigurableApplicationContext run(Class? primarySource, String... args) { // 会返回一个正在运行的Spring容器return run(new Class?[] { primarySource }, args); // 调用重载的run方法 } // 2. public static ConfigurableApplicationContext run(Class?[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); // 先调用该构造方法,然后再调用run方法将程序参数传进去 } // 3. public SpringApplication(Class?... primarySources) {this(null, primarySources); //primarySource 是传入的主配置类通常带有 SpringBootApplication 注解的类Spring Boot 会将其作为配置源。 }// 4. [构造方法] 构造方法 public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) {........ // 见下一节构造方法 }先调用该构造方法,然后再调用run方法 ①构造方法 public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) {this.resourceLoader resourceLoader; // null的Assert.notNull(primarySources, PrimarySources must not be null);this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); // 一、设置主配置类this.webApplicationType WebApplicationType.deduceFromClasspath(); // 二、推断应用类型this.bootstrapRegistryInitializers new ArrayList( // 三、getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 四、setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 五、this.mainApplicationClass deduceMainApplicationClass(); // 六、通过堆栈信息推断出主类即 main 方法所在的类。 }1.推断应用类型 WebApplicationType.deduceFromClasspath() 方法会根据类路径中是否存在特定的类来推断应用类型。可能的类型包括 WebApplicationType.SERVLET基于 Servlet 的 Web 应用如 Spring MVC。WebApplicationType.REACTIVE基于 Reactive 的 Web 应用如 Spring WebFlux。WebApplicationType.NONE非 Web 应用。 2.加载并初始化 BootstrapRegistryInitializer 实例 分析一下核心方法getSpringFactoriesInstances下面两个都会调用这个。 private T CollectionT getSpringFactoriesInstances(ClassT type, Class?[] parameterTypes, Object... args) {ClassLoader classLoader getClassLoader();// Use names and ensure unique to protect against duplicatesSetString names new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 下一步ListT instances createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances; }// SpringFactoriesLoader.loadFactoryNames(type, classLoader) 到这儿来了 public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse classLoader;if (classLoaderToUse null) {classLoaderToUse SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName factoryType.getName();return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }//loadSpringFactories(classLoaderToUse) private static MapString, ListString loadSpringFactories(ClassLoader classLoader) {// static final MapClassLoader, MapString, ListString cache new ConcurrentReferenceHashMap();// 从缓存map中拿到对应classLoader的map如果该classLoader已经存在了就不用走下面的了MapString, ListString result cache.get(classLoader);if (result ! null) {return result;}result new HashMap();try {/*public static final String FACTORIES_RESOURCE_LOCATION META-INF/spring.factories;结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。*/EnumerationURL urls classLoader.getResources(FACTORIES_RESOURCE_LOCATION);..............return result; }可以看到这里在第一章《注解自动配置》也出现了这个如今在SpringApplication的构造方法底层也调用到了这里。二者有什么区别或者联系呢 SpringFactoriesLoader.loadFactoryNames是Spring Boot 提供的工具方法用于从 META-INF/spring.factories 文件中加载指定类型的配置类。 两者都依赖于 META-INF/spring.factories 文件该文件是 Spring Boot 自动配置和扩展机制的核心配置文件。两者都通过类路径扫描加载所有 META-INF/spring.factories 文件并解析出指定类型的配置类。 1调用位置 AutoConfigurationImportSelector 位于 org.springframework.boot.autoconfigure 包中。是 Spring Boot 自动配置的核心组件之一负责加载自动配置类。在 Spring 容器的配置类解析阶段被调用具体是在 EnableAutoConfiguration 注解的处理过程中。 SpringApplication 位于 org.springframework.boot 包中。是 Spring Boot 应用的启动类负责初始化应用上下文、加载配置等。在应用启动时被调用。 2加载的配置类型 AutoConfigurationImportSelector 主要加载 META-INF/spring.factories 文件中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 键下的自动配置类。这些配置类用于实现 Spring Boot 的自动配置功能如 DataSourceAutoConfiguration、WebMvcAutoConfiguration 等。 SpringApplication 加载多种类型的配置类包括 ApplicationContextInitializerApplicationListenerBootstrapRegistryInitializer 这些配置类用于初始化应用上下文、监听应用事件等。 3调用时机 AutoConfigurationImportSelector 在 Spring 容器解析配置类时调用具体是在 ConfigurationClassPostProcessor 处理 Configuration 类时。属于 Spring 容器初始化的早期阶段。 SpringApplication 在应用启动时调用具体是在 SpringApplication 的构造方法或 run 方法中。属于应用启动的早期阶段。 4返回值的使用 AutoConfigurationImportSelector 返回的自动配置类会被 Spring 容器加载并处理最终生成相应的 Bean 定义。这些配置类通常包含 Configuration 注解和 Conditional 注解用于按需加载 Bean。 SpringApplication 返回的配置类会被直接实例化并注册到应用中。例如ApplicationContextInitializer 会被调用以初始化应用上下文ApplicationListener 会被注册以监听应用事件。 3.加载并设置 ApplicationContextInitializer 实例 同2 4.加载并设置 ApplicationListener 实例 同2 总结 BootstrapRegistryInitializer用于应用启动的最早阶段初始化引导阶段的组件。ApplicationContextInitializer用于在 ApplicationContext 创建之后、刷新之前对上下文进行自定义初始化。ApplicationListener用于监听应用生命周期中的事件并在特定阶段执行逻辑。 这三者共同扩展了 Spring Boot 应用的启动过程提供了灵活的扩展点可以满足不同场景下的需求。 5.三者的实现 分别编写实现类 public class MyBootstrapInit implements BootstrapRegistryInitializer {Overridepublic void initialize(BootstrapRegistry registry) {System.out.println(【MyBootstrapInit】--------------方法执行了);} }public class MyApplicationContextInit implements ApplicationContextInitializerConfigurableApplicationContext {Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println(【MyApplicationContextInit】------------ applicationContext.getApplicationName());} }public class MyContextListener implements ApplicationListenerApplicationStartedEvent { // 该监听器对此事件感兴趣Overridepublic void onApplicationEvent(ApplicationStartedEvent event) {System.out.println(【MyContextListener】--监听器-- event.getSource());} }然后在resource目录下面创建META-INF在其中的spring.factories中 org.springframework.boot.BootstrapRegistryInitializercom.feng.tackle.config.source.MyBootstrapInit org.springframework.context.ApplicationContextInitializercom.feng.tackle.config.source.MyApplicationContextInit org.springframework.context.ApplicationListenercom.feng.tackle.config.source.MyContextListener启动应用 疑问 我可以在这三者的实现类上面加Configuration注解不要spring.factories可以实现类似效果吗 答案是只有ApplicationListener可以。为什么请看下面的run方法里面 ②run public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间用于后续计算启动耗时。long startTime System.nanoTime(); //创建一个 BootstrapContext用于在应用启动的早期阶段提供一些基础设施支持如环境配置、属性源等DefaultBootstrapContext bootstrapContext createBootstrapContext();ConfigurableApplicationContext context null;// 设置系统属性 java.awt.headless确保应用在没有图形界面环境如服务器中也能正常运行configureHeadlessProperty();/*获取所有 SpringApplicationRunListener 实例用于监听应用启动的各个阶段。调用 listeners.starting()通知监听器应用正在启动。*/SpringApplicationRunListeners listeners getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments new DefaultApplicationArguments(args);// 加载和配置应用的环境Environment包括配置文件如 application.properties 或 application.yml、命令行参数等。ConfigurableEnvironment environment prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印 Spring Boot 的启动 Banner默认或自定义。Banner printedBanner printBanner(environment);// 根据应用类型Servlet、Reactive 等创建相应的 ApplicationContext。context createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备应用上下文prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 调用 AbstractApplicationContext.refresh() 方法完成 Bean 的实例化、依赖注入和初始化。refreshContext(context);afterRefresh(context, applicationArguments);// 计算启动耗时并记录日志。Duration timeTakenToStartup Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);// 执行所有 ApplicationRunner 和 CommandLineRunner 的实现类用于在应用启动后执行自定义逻辑。callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 计算应用启动到就绪的总耗时。Duration timeTakenToReady Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context; }这个run这里分析得不够深入。受篇幅影响在后续文章中再来分析。 end. 参考 尚硅谷雷丰阳老师的课
http://www.tj-hxxt.cn/news/140589.html

相关文章:

  • 温州建设信息网站深圳的深圳的网站建设公司
  • 长春制作门户网站的公司搭建 网站 模版
  • 房产网站建设产品设计网站官网
  • 专门做水生植物销售网站杭州萧山区抖音seo排行榜
  • 网站定制公司排行榜seo索引擎优化
  • 制作网站监控推荐莆田网站建设开发
  • 初中网站建设网站建设的实施方案
  • 攀枝花仁和住房和城乡建设局网站网站建设费用分类
  • 网站开发参考文献期刊学网站设计
  • 溧水区住房和城乡建设厅网站哪里做网站比较快
  • 旅游门户网站建设项目招标佛山网站设计制作公司
  • 做儿童文学有哪些的网站seo优化排名易下拉用法
  • 自己做的网站如何兼容莱芜金点子最新招聘
  • 南充网站建设工作室有阿里云服务器 怎么做网站
  • 惠城中山网站建设四合一小说网站搭建教程
  • 免费建个人手机网站网站建设的资金
  • 网站开发前端工程师建好的网站怎么用
  • 常德投诉网站秦皇岛网站建设找汉狮
  • 山东鲁桥建设有限公司网站中国核工业二四建设有限公司
  • 微网站建设报价表网络营销的特点包括什么
  • 网站建设968WordPress的插件怎么保存
  • 网站不用域名可以吗石家庄建设路网站
  • 金融交易网站开发wordpress添加媒体没反应
  • 域名站长工具创办公司需要多少资金
  • 活动网站网易云播放器做网站播放
  • 在线网页代理网址seo网络优化公司哪家好
  • 企业培训机构网站源码做网站哪个公司最好
  • 西安网站开发定制制作清河做网站哪家好
  • 石家庄做公司网站创意网站开发
  • 手机网站开发成本哈尔滨住房和城乡建设局