概述
我们的所有微服务若想集成Swagger在线接口文档,都需要在各自模块中建立一个Swagger的配置类,关键代码如下:
@Configuration @EnableSwagger2 publicclass SwaggerConfig { privatestaticfinal String VERSION = "1.0.0"; /** * 创建API */ @Bean public Docket createRestApi(){ returnnew Docket(DocumentationType.SWAGGER_2) .enable(true) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .paths(PathSelectors.any()) .build(); } /** * 添加摘要信息 */ private ApiInfo apiInfo() { returnnew ApiInfoBuilder() .title("product-server接口文档") .contact(new Contact("JAVA日知录","http://javadaily.cn","jianzh5@163.com")) .description("product-server接口文档") .version(VERSION) .build(); } }
这样每个模块中都有一个SwaggerConfig
配置类,他们的逻辑基本都一样,只是一些摘要信息不一样。这明显也算是违反了 DRY(Don't Repeat Yourself)
原则,这次我们来优化优化它,通过修改配置文件让Swagger自动配置。
不过在编写代码之前我们还是需要先了解一下SpringBoot的自动配置原理。
SpringBoot自动配置原理
SpringBoot项目启动类上都会添加@SpringBootApplication
注解,这个注解是个组合注解,他的核心功能是开启自动配置注解@EnableAutoConfiguration
,如下图所示:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public@interface EnableAutoConfiguration { 。。。 }
@EnableAutoConfiguration
又通过@Import
注解导入了AutoConfigurationImportSelector
。通过对AutoConfigurationImportSelector
中 selectImports
方法的跟踪,我们找到SpringBoot启动时会通过SpringFactoriesLoader.loadFactoryNames
方法 从 META-INF/spring.factories
这个文件下去寻找有没有自动配置类。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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; }
spring.factories
在项目中打开spring-boot-autoconfigure-2.1.9.RELEASE.jar,然后在META-INF
文件夹下打开spring.factories
,截取部分内容如下:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
这个文件是一组的key=value的形式,通过value找到了自定义配置类,这里选取一个我们比较常见的配置类org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
,打开源码:
@Configuration @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class}) @EnableConfigurationProperties({DataSourceProperties.class}) @Import({DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class}) publicclass DataSourceAutoConfiguration { ... }
这里我们又发现配置类上使用了@EnableConfigurationProperties({DataSourceProperties.class})
,这个注解是去加载配置类。
application.properties
再打开DataSourceProperties.class
,代码如下:
@ConfigurationProperties( prefix = "spring.datasource" ) publicclass DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private ClassLoader classLoader; private String name; privateboolean generateUniqueName; private Class<? extends DataSource> type; private String driverClassName; private String url; private String username; private String password; ... }
看到这里大家都应该很熟悉了,主要是通过注解 @ConfigurationProperties
从配置文件中加载spring.datasource开头的配置,如我们经常用的数据库配置
spring: datasource: type:com.zaxxer.hikari.HikariDataSource url:jdbc:mysql://xxxxxxx/cloud_alibaba?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false username:xxx password:xxxxxx driver-class-name:com.mysql.jdbc.Driver
从配置文件获取相关配置注入到DataSourceProperties这个类中
总结
通过观察源码我们找到了SpringBoot自定义配置类的加载过程,主要是从META-INF/spring.factories
找到对应的启动类,启动类上再通过配置类加载配置文件。说起来很简单,但是实现起来还是很复杂的。接下来我们就根据我们的理解来完成Swagger的自动配置。
自定义Swagger自动配置
这里可能有人会问,虽然看完了自定义配置的加载逻辑,但是还是不会写怎么办?
不会写没关系啊,咱们不是会复制粘贴吗?
我们以org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
为例,开始我们的自定义配置(Copy,Paste)过程
建立配置文件
我们在common
模块建立resources/META-INF/spring.factories
文件,粘贴上面的配置进行修改
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.javadaily.autoconfigure.SwaggerAutoConfiguration
建立配置类,从配置文件读取配置
先想想我们需要哪些配置,一个title
,一个description
,还有一个enable
用来控制是否开放在线测试,分析清楚了我们就建立对应的配置类SwaggerProperties
@Data @ConfigurationProperties(prefix = "javadaily.swagger") publicclass SwaggerProperties { /** * 是否启用swagger,生产环境建议关闭 */ privateboolean enabled; /** * 文档标题 */ private String title; /** * 文档描述 */ private String description; }
建立自定义配置类
核心代码,但是实现起来比较简单。
拷贝原来的配置类内容,加上相关注解,注入配置类,将原来写死的地方改成从配置类获取即可。
@Slf4j @Configuration //注入配置类 @EnableConfigurationProperties({SwaggerProperties.class}) //根据配置文件决定是否自动配置 @ConditionalOnProperty(prefix = "javadaily.swagger", name = "enabled", havingValue = "true") @Import({Swagger2DocumentationConfiguration.class}) publicclass SwaggerConfig { privatestaticfinal String VERSION = "1.0.0"; private SwaggerProperties swaggerProperties; public SwaggerAutoConfiguration (SwaggerProperties swaggerProperties){ this.swaggerProperties = swaggerProperties; } /** * 创建API */ @Bean public Docket createRestApi(){ returnnew Docket(DocumentationType.SWAGGER_2) .enable(true) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .paths(PathSelectors.any()) .build(); } /** * 添加摘要信息 */ private ApiInfo apiInfo() { returnnew ApiInfoBuilder() .contact(new Contact("JAVA日知录","http://javadaily.cn","jianzh5@163.com")) .title(swaggerProperties.getTitle()) .description(swaggerProperties.getDescription()) .version(VERSION) .build(); } }
在微服务层的配置文件上加入swagger相关的配置
## swagger自定义配置属性 javadaily: swagger: enabled:true title:account-service在线接口平台 description:account-service微服务相关接口
注意:这里配置文件需要以javadaily.swagger前缀开始,跟上面的配置类相对应
经过以上四步我们完成了Swagger的自定义自动配置,接下来就是在服务层引入common模块,然后删除掉SwaggerConfig类,让common模块给我们自动配置。
是不是很简单呢,你们也来试试吧!
好了,各位朋友们,本期的内容到此就全部结束啦,能看到这里的同学都是优秀的同学,下一个升职加薪的就是你了!