引言
spring boot 的便利体现在,它简化了很多繁琐的配置,这对开发人员来说是一个福音。只要引入框架的starter就可以使用框架的功能了。不过当出现错误时,排查问题的难度就上升了。因为自动配置的逻辑都在spring boot starter中,想要快速定位问题,就必须了解spring boot starter的内部原理。下面我们自己动手来实现一个spring boot starter
——《spring cloud 微服务 入门、进阶与实战》25页
spring boot starter 项目创建 创建一个项目 spring-starter-demo。
注意!!!
这里创建的不是spring boot ,也不是 maven web。因为试过,即使 maven install 成功生成了一个starter的 jar 包,但在spring boot 项目中却不能正常注入。经查多篇博客发现这里创建的是maven quick start 项目 (有的说是 j2ee - simple 我还没检验 )。
项目最终目录结构如下:
创建好后包(自定义的包名)com.study 下面原本只有一个 App类(这个App.class 在这个starter 项目中没有任何作用,可以删除掉,不删掉也不影响)。
其它类是后面添加的。resources 资源文件夹也是后面自己添加的,创建完是没有的。
pom配置如下:(手动添加的已做标注,其它的都是自动生成的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.study</groupId > <artifactId > spring-starter-demo</artifactId > <version > 1.0-SNAPSHOT</version > <name > spring-starter-demo</name > <url > http://www.example.com</url > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.1.8.RELEASE</version > <relativePath /> </parent > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.source > 1.7</maven.compiler.source > <maven.compiler.target > 1.7</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.11</version > <scope > test</scope > </dependency > </dependencies > <build > <pluginManagement > <plugins > <plugin > <artifactId > maven-clean-plugin</artifactId > <version > 3.1.0</version > </plugin > <plugin > <artifactId > maven-resources-plugin</artifactId > <version > 3.0.2</version > </plugin > <plugin > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.0</version > </plugin > <plugin > <artifactId > maven-surefire-plugin</artifactId > <version > 2.22.1</version > </plugin > <plugin > <artifactId > maven-jar-plugin</artifactId > <version > 3.0.2</version > </plugin > <plugin > <artifactId > maven-install-plugin</artifactId > <version > 2.5.2</version > </plugin > <plugin > <artifactId > maven-deploy-plugin</artifactId > <version > 2.8.2</version > </plugin > <plugin > <artifactId > maven-site-plugin</artifactId > <version > 3.7.1</version > </plugin > <plugin > <artifactId > maven-project-info-reports-plugin</artifactId > <version > 3.0.0</version > </plugin > </plugins > </pluginManagement > </build > </project >
UserProperties
1 2 3 4 5 6 7 @Configuration @ConfigurationProperties("spring.user") public class UserProperties { private String username; private String pwd; }
UserClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class UserClient { private UserProperties userProperties; public UserClient () { } public UserClient (UserProperties p) { this .userProperties = p; } public String getName () { return userProperties.getUsername(); } public String getPwd () { return userProperties.getPwd(); } }
UserAutoConfigure
1 2 3 4 5 6 7 8 9 10 11 @Configuration @EnableConfigurationProperties(UserProperties.class) public class UserAutoConfigure { @Bean @ConditionalOnProperty(prefix = "spring.user",value = "enabled",havingValue = "true") public UserClient userClient (UserProperties userProperties) { return new UserClient (userProperties); } }
spring.factories
1 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration =\ com.study.UserAutoConfigure
maven打包 这里用maven clean; maven install.(如果已经配置好的话。直接点击idea右边的maven命令即可)
那么这个 starter 就制作好了
引入stater 在springboot 中引入:
1 2 3 4 5 <dependency > <groupId > com.study</groupId > <artifactId > spring-starter-demo</artifactId > <version > 1.0-SNAPSHOT</version > </dependency >
我这里引入是提示没找到。没有关系,
只要这里注入时没有提示错误就可以
1 2 3 4 5 6 7 8 @Autowired private UserClient userClient;@GetMapping("/user/name") public String getUserName () { logger.info("lalalalalalallalala" + userClient.toString()); return userClient.getName(); }
在spring boot 项目配置文件中加入:
1 2 3 spring.user.username =WuZhiYong spring.user.pwd =123456 spring.user.enabled =true
启动项目,请求测试地址得到返回:
使用注解开启自动构建 starter项目里建立一个类(我是放在同包下,这个位置应该没什么关系)
1 2 3 4 5 6 7 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(UserAutoConfigure.class) public @interface EnableUserClient {}
这里可以把resource 下 META-INF 里边的spring.factories 删掉了。然后在spring boot项目 的启动类上加入注解
启动spring boot 访问测试地址 同样也能得到想要的结果
使用配置开启自动构建 这一点其实已经结合在前面的配置中了
在类UserAutoConfigure里注解@ConditionalOnProperty,就表示必须配置文件中指定,spring.user.enabled=true
这里才会构建这个bean
1 @ConditionalOnProperty(prefix = "spring.user",value = "enabled",havingValue = "true")
例如在springboot 中我们把spring.user.enabled=true 注释掉再启动项目会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Field userClient in com.example.springbootbase.controller.HelloController required a bean of type 'com.study.UserClient' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true ) The following candidates were found but could not be injected: - Bean method 'userClient' in 'UserAutoConfigure' not loaded because @ConditionalOnProperty (spring.user.enabled=true ) did not find property 'enabled' Action: Consider revisiting the entries above or defining a bean of type 'com.study.UserClient' in your configuration. Process finished with exit code 0
在实际的场景中我们自定义的starter 功能肯定不会这么单一,在UserAutoConfigure中定会有多个bean。这些bean 我们根据功能模块的不同进行封装后,通过如上@ConditionalOnProperty的配置。在实际应用时,我们可通过配置 不同的enable=true来加载不同的功能。
这就是使用配置开启自动构建。
配置starter内容提示 在starter项目里 resources 的META-INF下建立spring-configuration-metadata.json文件
写入如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "properties" : [ { "name" : "spring.user.username" , "defaultValue" : "wu_zhi_yong999" } , { "name" : "spring.user.pwd" , "defaultValue" : "lalalalalla" } , { "name" : "spring.user.enabled" , "type" : "java.lang.Boolean" , "defaultValue" : false } ] }
重新 clean install
在spring boot 项目里我们配置spring.user. 会有自动提示 :
后续 spring 自定义 starter 还有很多值得深究的地方。我在抄写代码时抄错了(抄都能抄错 哎 以后只能 CV了) 后来造成不能配置使用starter 。在网上看了很多博客。虽然最后发现了是自己的问题(抄错了)。但也发现了很不错的文章 这里分享下:
https://blog.csdn.net/qq_31445987/article/details/105152837?utm_source=distribute.pc_relevant.none-task-blog-baidujs-2
https://blog.csdn.net/qq_25863973/article/details/99343187?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1
这几天都是在参照《spring cloud 微服务 入门、进阶与实战》这本书在学习。接下来终于要开始spring cloud 了
参考:
《spring cloud 微服务 入门、进阶与实战》