玩转 Spring Boot 原理篇(核心注解知多少)

Posted 一猿小讲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转 Spring Boot 原理篇(核心注解知多少)相关的知识,希望对你有一定的参考价值。

type = FilterType.CUSTOM, classes = TypeExcludeFilter.class type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.classSpringBootApplication SpringBootConfiguration ComponentScan EnableAutoConfiguration EnableAutoConfiguration * Environment property that can be used to override when auto-configuration is * enabled. */ String ENABLED_OVERRIDE_PROPERTY = * Exclude specific auto-configuration classes such that they will never be applied. * the classes to exclude */ Class<?>[] exclude() ; * Exclude specific auto-configuration class names such that they will never be * applied. * the class names to exclude * 1.3.0 */ String[] excludeName() ;


从 @EnableAutoConfiguration 源代码可以看出,其内部引入了 @AutoConfigurationPackage 和 @Import 这两个注解。@AutoConfigurationPackage 的作用是自动配置包;@Import 则是导入需要自动配置的组件。



回头瞅瞅,Spring Boot 对 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan  等重要的注解的配置做了简化封装,在代码开发时只需 @SpringBootApplication 这一个复合注解就轻松开启 Spring 组件扫描和 Spring Boot 自动配置的功能,可谓是化繁为简,So Cool~。


3. 例行回顾

本文基于源码对 Spring Boot 的核心注解设计大概了解,重在体会 Spring Boot 架构的设计思想。


文末提到了 @EnableAutoConfiguration 这个 Spring Boot 自动装配的功臣,哪么 Spring Boot 自动装配是如何实现的呢?下次我们将顺着主线往下捋,感兴趣的可以顺着我画的这个流程图先自己体会体会自动装配的思想。

一起聊技术、谈业务、喷架构,少走弯路,不踩大坑,会持续输出更多精彩分享,欢迎关注,敬请期待!

玩转 Spring Boot 原理篇(源码环境搭建)

There were failing tests. See the report at: file:///Users/tangbao/growup/spring-boot-2.6.3/buildSrc/build/reports/tests/test/index.html

org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:75 org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:164 org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:196 org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:135

* src/test/java/org/springframework/boot/build/bom/BomPluginIntegrationTests.java org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:81 java.lang.RuntimeException at BomPluginIntegrationTests.java:168 Caused by: javax.xml.xpath.XPathExpressionException at BomPluginIntegrationTests.java:168 Caused by: javax.xml.transform.TransformerException at BomPluginIntegrationTests.java:168 Caused by: java.lang.RuntimeException at BomPluginIntegrationTests.java:168 Caused by: javax.xml.xpath.XPathExpressionException at BomPluginIntegrationTests.java:168 Caused by: javax.xml.transform.TransformerException at BomPluginIntegrationTests.java:168 Caused by: java.lang.RuntimeException at BomPluginIntegrationTests.java:168 org.opentest4j.AssertionFailedError at BomPluginIntegrationTests.java:198* Copyright 2012-2021 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/* Tests for @link BomPlugin.** @author Andy Wilkinson*/ private File projectDir; private File buildFile; @BeforeEach void setup(@TempDir File projectDir) throws IOException this.projectDir = projectDir; this.buildFile = new File(this.projectDir, "build.gradle"); @Test void libraryModulesAreIncludedInDependencyManagementOfGeneratedPom() throws IOException try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'ActiveMQ\', \'5.15.10\') "); out.println(" group(\'org.apache.activemq\') "); out.println(" modules = ["); out.println(" \'activemq-amqp\',"); out.println(" \'activemq-blueprint\'"); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/activemq.version").isEqualTo("5.15.10"); NodeAssert dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[1]"); assertThat(dependency).textAtPath("groupId").isEqualTo("org.apache.activemq"); assertThat(dependency).textAtPath("artifactId").isEqualTo("activemq-amqp"); // assertThat(dependency).textAtPath("version").isEqualTo("$activemq.version"); assertThat(dependency).textAtPath("scope").isNullOrEmpty(); assertThat(dependency).textAtPath("type").isNullOrEmpty(); dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[2]"); assertThat(dependency).textAtPath("groupId").isEqualTo("org.apache.activemq"); assertThat(dependency).textAtPath("artifactId").isEqualTo("activemq-blueprint"); // assertThat(dependency).textAtPath("version").isEqualTo("$activemq.version"); assertThat(dependency).textAtPath("scope").isNullOrEmpty(); assertThat(dependency).textAtPath("type").isNullOrEmpty(); ); @Test void libraryPluginsAreIncludedInPluginManagementOfGeneratedPom() throws IOException try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'Flyway\', \'6.0.8\') "); out.println(" group(\'org.flywaydb\') "); out.println(" plugins = ["); out.println(" \'flyway-maven-plugin\'"); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/flyway.version").isEqualTo("6.0.8"); NodeAssert plugin = pom.nodeAtPath("//pluginManagement/plugins/plugin"); assertThat(plugin).textAtPath("groupId").isEqualTo("org.flywaydb"); assertThat(plugin).textAtPath("artifactId").isEqualTo("flyway-maven-plugin"); assertThat(plugin).textAtPath("version").isEqualTo("$flyway.version"); assertThat(plugin).textAtPath("scope").isNullOrEmpty(); assertThat(plugin).textAtPath("type").isNullOrEmpty(); ); @Test void libraryImportsAreIncludedInDependencyManagementOfGeneratedPom() throws Exception try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'Jackson Bom\', \'2.10.0\') "); out.println(" group(\'com.fasterxml.jackson\') "); out.println(" imports = ["); out.println(" \'jackson-bom\'"); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/jackson-bom.version").isEqualTo("2.10.0"); NodeAssert dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency"); assertThat(dependency).textAtPath("groupId").isEqualTo("com.fasterxml.jackson"); assertThat(dependency).textAtPath("artifactId").isEqualTo("jackson-bom"); // assertThat(dependency).textAtPath("version").isEqualTo("$jackson-bom.version"); assertThat(dependency).textAtPath("scope").isEqualTo("import"); assertThat(dependency).textAtPath("type").isEqualTo("pom"); ); @Test void moduleExclusionsAreIncludedInDependencyManagementOfGeneratedPom() throws IOException try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'MySQL\', \'8.0.18\') "); out.println(" group(\'mysql\') "); out.println(" modules = ["); out.println(" \'mysql-connector-java\' "); out.println(" exclude group: \'com.google.protobuf\', module: \'protobuf-java\'"); out.println(" "); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/mysql.version").isEqualTo("8.0.18"); NodeAssert dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency"); assertThat(dependency).textAtPath("groupId").isEqualTo("mysql"); assertThat(dependency).textAtPath("artifactId").isEqualTo("mysql-connector-java"); // assertThat(dependency).textAtPath("version").isEqualTo("$mysql.version"); assertThat(dependency).textAtPath("scope").isNullOrEmpty(); assertThat(dependency).textAtPath("type").isNullOrEmpty(); NodeAssert exclusion = dependency.nodeAtPath("exclusions/exclusion"); // assertThat(exclusion).textAtPath("groupId").isEqualTo("com.google.protobuf"); // assertThat(exclusion).textAtPath("artifactId").isEqualTo("protobuf-java"); ); @Test void moduleTypesAreIncludedInDependencyManagementOfGeneratedPom() throws IOException try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'Elasticsearch\', \'7.15.2\') "); out.println(" group(\'org.elasticsearch.distribution.integ-test-zip\') "); out.println(" modules = ["); out.println(" \'elasticsearch\' "); out.println(" type = \'zip\'"); out.println(" "); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/elasticsearch.version").isEqualTo("7.15.2"); NodeAssert dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency"); assertThat(dependency).textAtPath("groupId").isEqualTo("org.elasticsearch.distribution.integ-test-zip"); assertThat(dependency).textAtPath("artifactId").isEqualTo("elasticsearch"); // assertThat(dependency).textAtPath("version").isEqualTo("$elasticsearch.version"); assertThat(dependency).textAtPath("scope").isNullOrEmpty(); // assertThat(dependency).textAtPath("type").isEqualTo("zip"); assertThat(dependency).nodeAtPath("exclusions").isNull(); ); @Test void libraryNamedSpringBootHasNoVersionProperty() throws IOException try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) out.println("plugins "); out.println(" id \'org.springframework.boot.bom\'"); out.println(""); out.println("bom "); out.println(" library(\'Spring Boot\', \'1.2.3\') "); out.println(" group(\'org.springframework.boot\') "); out.println(" modules = ["); out.println(" \'spring-boot\'"); out.println(" ]"); out.println(" "); out.println(" "); out.println(""); generatePom((pom) -> assertThat(pom).textAtPath("//properties/spring-boot.version").isEmpty(); NodeAssert dependency = pom.nodeAtPath("//dependencyManagement/dependencies/dependency[1]"); assertThat(dependency).textAtPath("groupId").isEqualTo("org.springframework.boot"); assertThat(dependency).textAtPath("artifactId").isEqualTo("spring-boot"); assertThat(dependency).textAtPath("version").isEqualTo("1.2.3"); assertThat(dependency).textAtPath("scope").isNullOrEmpty(); assertThat(dependency).textAtPath("type").isNullOrEmpty(); ); // @Test // void versionAlignmentIsVerified() throws IOException // try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) // out.println("plugins "); // out.println(" id \'org.springframework.boot.bom\'"); // out.println(""); // out.println("bom "); // out.println(" library(\'OAuth2 OIDC SDK\', \'8.36.1\') "); // out.println(" alignedWith(\'Spring Security\') "); // out.println( // " // source(\'https://github.com/spring-projects/spring-security/blob/$libraryVersion/config/gradle/dependency-locks/optional.lockfile\')"); // out.println(" pattern(\'com.nimbusds:oauth2-oidc-sdk:(.+)\')"); // out.println(" "); // out.println(" group(\'com.nimbusds\') "); // out.println(" modules = ["); // out.println(" \'oauth2-oidc-sdk\'"); // out.println(" ]"); // out.println(" "); // out.println(" "); // out.println(" library(\'Spring Security\', \'5.4.7\') "); // out.println(" "); // out.println(""); // // System.out.println(runGradle(DeployedPlugin.GENERATE_POM_TASK_NAME, // "-s").getOutput()); // private BuildResult runGradle(String... args) return GradleRunner.create().withDebug(true).withProjectDir(this.projectDir).withArguments(args) .withPluginClasspath().build(); private void generatePom(Consumer<NodeAssert> consumer) runGradle(DeployedPlugin.GENERATE_POM_TASK_NAME, "-s"); File generatedPomXml = new File(this.projectDir, "build/publications/maven/pom-default.xml"); assertThat(generatedPomXml).isFile(); consumer.accept(new NodeAssert(generatedPomXml)); public static void main(String[] args) System.out.println("Spring Boot 源码剖析之源码环境搭建验证"); SpringApplication.run(DemoApplication.class, args); System.out.println("Spring Boot 源码剖析之源码环境搭建验证成功");

直接运行,控制台输出如下。


至此 IDEA + Gradle 7.4 +Spring Boot 2.6.3 源码环境就搭建完成了。


5. 例行回顾

本文是玩转 Spring Boot 原理篇的首篇,主要是一起学习了 Spring Boot 源码环境搭建,看似一个简单的过程,中途也确实遇到了不少问题,不过最终还是成功了。

为了后续能够清晰的读源码,还是需要提前制定目标,提前预设一下问题,这样带着问题去分析学习源码,效果会更好,你会关注 Spring Boot 哪些常见的问题呢?不知你脑海里是否会浮现如下问题呢?

  • Spring Boot 的核心注解有哪些?

  • Spring Boot 自动装配的原理是啥?

  • Spring Boot 启动机制,背后都做了哪些操作呢?

  • Spring Boot 内嵌 Tomcat 是如何启动的呢?

  • ... ...

  • 携带这些主流的问题,让我们一起踏入 Spring Boot 源码学习剖析之门

    以上是关于玩转 Spring Boot 原理篇(核心注解知多少)的主要内容,如果未能解决你的问题,请参考以下文章

    玩转 Spring Boot 原理篇(自动装配源码剖析)

    玩转 Spring Boot 原理篇(内嵌Tomcat实现原理&优雅停机源码剖析)

    玩转 Spring Boot 原理篇(自动装配前凑之自定义Stater)

    Spring Boot 运行原理 - 核心注解

    Spring Boot核心原理实现及核心注解类

    《02.Spring Boot连载:Spring Boot实战.Spring Boot核心原理剖析》