zoukankan      html  css  js  c++  java
  • SpringCloud Alibaba微服务番外一

    概述

    我们的所有微服务若想集成Swagger在线接口文档,都需要在各自模块中建立一个Swagger的配置类,关键代码如下:

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        private static final String VERSION = "1.0.0";
        /**
         * 创建API
         */
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.SWAGGER_2)
    			.enable(true)
    			.apiInfo(apiInfo())
    			.select()
    			.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
    			.paths(PathSelectors.any())
    			.build();
        }
    
        /**
         * 添加摘要信息
         */
        private ApiInfo apiInfo() {
            return new 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。通过对AutoConfigurationImportSelectorselectImports 方法的跟踪,我们找到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})
    public class DataSourceAutoConfiguration {
    	...
    }
    

    这里我们又发现配置类上使用了@EnableConfigurationProperties({DataSourceProperties.class}),这个注解是去加载配置类。

    application.properties

    再打开DataSourceProperties.class,代码如下:

    @ConfigurationProperties(
        prefix = "spring.datasource"
    )
    public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
        private ClassLoader classLoader;
        private String name;
        private boolean 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")
    public class SwaggerProperties {
        /**
         * 是否启用swagger,生产环境建议关闭
         */
        private boolean enabled;
        /**
         * 文档标题
         */
        private String title;
        /**
         * 文档描述
         */
        private String description;
    }
    

    建立自定义配置类

    核心代码,但是实现起来比较简单。
    拷贝原来的配置类内容,加上相关注解,注入配置类,将原来写死的地方改成从配置类获取即可。

    @Slf4j
    @Configuration
    //注入配置类
    @EnableConfigurationProperties({SwaggerProperties.class}) 
    //根据配置文件决定是否自动配置
    @ConditionalOnProperty(prefix = "javadaily.swagger", name = "enabled", havingValue = "true")
    @Import({Swagger2DocumentationConfiguration.class})
    public class SwaggerConfig {
        private static final String VERSION = "1.0.0";
    	private SwaggerProperties swaggerProperties;
        public SwaggerAutoConfiguration (SwaggerProperties swaggerProperties){
            this.swaggerProperties = swaggerProperties;
        }
        /**
         * 创建API
         */
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.SWAGGER_2)
    			.enable(true)
    			.apiInfo(apiInfo())
    			.select()
    			.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
    			.paths(PathSelectors.any())
    			.build();
        }
    
        /**
         * 添加摘要信息
         */
        private ApiInfo apiInfo() {
            return new 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模块给我们自动配置。

    是不是很简单呢,你们也来试试吧!

    系列文章
    SpringCloud 系列

    在这里插入图片描述

  • 相关阅读:
    .netcore返回HellowWorld四种方式(管道配置,管道扩展方法,中间件,IStartupFilter 使用中间件的升级扩展)
    Mysql分页大数据量查询优化
    swagger发布本地的调试的时候没事,发布服务器提示500 : {"Message":"出现错误。"}
    DBeaver的使用(impala和数据库)
    mysql远程连接问题
    java+thymeleaf-layout-dialect+thymeleaf的使用
    springboot+thyemeleaf+swagger项目的创建和问题的解决
    ffmpeg实践
    Camera.main
    python双曲线拟合
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13295894.html
Copyright © 2011-2022 走看看