美文网首页
尝鲜Spring Cloud 2020.0.0

尝鲜Spring Cloud 2020.0.0

作者: EasyNetCN | 来源:发表于2020-12-23 15:04 被阅读0次

基于Spring Boot 2.4.1的Spring Cloud 2020.0.0(https://spring.io/blog/2020/12/22/spring-cloud-2020-0-0-aka-ilford-is-available)发布了,今天差不多花了6个多小时找了一个项目进行升级改造,终于跑了起来,进行了以下修改(仅供参考)

pom.xml

<?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></groupId>
    <artifactId></artifactId>
    <version></version>

    <name>operation platform</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>15</java.version>
        <hikaricp.version>3.4.5</hikaricp.version>
        <mysql.version>8.0.21</mysql.version>
        <guava.version>30.1-jre</guava.version>
        <poi.version>4.1.2</poi.version>
        <logstash-logback-encoder.version>6.5</logstash-logback-encoder.version>
        <jib-maven-plugin.version>2.7.0</jib-maven-plugin.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
    </parent>

    <repositories>
        <repository>
            <id>aliyun</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>aliyun</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        </pluginRepository>
    </pluginRepositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-all</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-kafka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>${guava.version}</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>${logstash-logback-encoder.version}</version>
        </dependency>
        <dependency>
            <groupId>com.belerweb</groupId>
            <artifactId>pinyin4j</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.google.cloud.tools</groupId>
                <artifactId>jib-maven-plugin</artifactId>
                <version>${jib-maven-plugin.version}</version>
                <configuration>
                    <from>
                        <image>adoptopenjdk:15.0.1_9-jre-hotspot</image>
                    </from>
                    <to>
                        <image>${project.artifactId}:${project.version}</image>
                    </to>
                    <container>
                        <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
                        <environment>
                            <TZ>Asia/Shanghai</TZ>
                        </environment>
                    </container>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

bootstrap.yml修改为application.yml,其中配置结构有了较大的变化

spring:
  application:
    name: operation-platform
  config:
    import:
    - consul:${consul.host}:${consul.port:8500}
  profiles:
    include:
    - common
---
spring: 
  config:
    activate:
      on-profile:
      - common
  codec:
    max-in-memory-size:
      -1
  cloud:
    consul:
      discovery:
        prefer-ip-address: true
        health-check-critical-timeout: 30s
      config:
        enabled: true
        prefix: ydyun360-config
        format: yaml
        default-context: ${spring.application.name}
    loadbalancer:
      ribbon:
        enabled: true
    stream:
      kafka:
        binder:
          brokers: ${kafka.brokers:localhost:9092}
          auto-add-partitions: false
          auto-create-topics: false
      bindings:
        log-service-topic-output: # 消息订阅通道
          destination: log-service-topic  # topic
          contentType: application/json
          producer:
            partition-key-expression:  headers['partitionKey']
            partition-count: 2
      default-binder: kafka
  cache:
    redis:
      key-prefix: ${spring.application.name}
      time-to-live: 0
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone:
      Asia/Shanghai
  kafka:
    bootstrap-servers: ${spring.cloud.stream.kafka.binder.brokers}
  session:
    timeout: 30d
    redis:
      namespace: ${spring.application.name}
  jpa:
    show-sql: false
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 500
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true
        rewriteBatchedStatements: true
        cacheResultSetMetadata: true
        cacheServerConfiguration: true
        elideSetAutoCommits: true
        maintainTimeStats: false
feign:
  httpclient:
    enabled: false
  okhttp:
    enabled: true
  client:
    config:
      default:
        read-timeout: 3600000
ribbon:
  eager-load:
    enabled: true
    clients: file-service,goods-service,user-service
  ConnectTimeout: 10000
  ReadTimeout: 3600000

logging:
  level:
    root: INFO
  file: 
    name: logs/${spring.application.name}.log

server:
  http2:
    enabled: true
  compression:
    enabled: true
    mime-types: application/json,application/xml,text/html,text/javascript,text/css,text/xml,text/plain
    min-response-size: 2048
  port: 9003

---
spring: 
  config:
    activate:
      on-profile:
      - development-local

---
spring:
  config:
    activate:
      on-profile:
      - development-test
  cloud:
    consul:
      host: ${consul.host:}
      port: ${consul.port:}
  
---
spring:
  config:
    activate:
      on-profile:
      - development-rc
  cloud:
    consul:
      host: ${consul.host:}
      port: ${consul.port:}

---
spring:
  config:
    activate:
      on-profile:
      -  testing

---
spring:
  config:
    activate:
      on-profile:
      - release

---
spring:
  config:
    activate:
      on-profile:
      - production

启动时候可以设置当前激活的profile

--spring.profiles.active=development-test --consul.host= --consul.port=

全局异常处理修改

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.HashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import com.fasterxml.jackson.databind.ObjectMapper;

import reactor.core.publisher.Mono;

@Component
@Order(-2)
public class GlobalDefaultExceptionHandler extends DefaultErrorWebExceptionHandler {
    private static final Log logger = LogFactory.getLog(GlobalDefaultExceptionHandler.class);

    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${spring.profiles.active}")
    private String profile;

    @Autowired
    private ConsulRegistration consulRegistration;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private LogStreams logStreams;

    public GlobalDefaultExceptionHandler(ErrorAttributes errorAttributes, ApplicationContext applicationContext,
            ServerCodecConfigurer serverCodecConfigurer) {
        super(errorAttributes, new Resources(), new ErrorProperties(), applicationContext);
        super.setMessageWriters(serverCodecConfigurer.getWriters());
        super.setMessageReaders(serverCodecConfigurer.getReaders());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    @Override
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        var errorPropertiesMap = getErrorAttributes(request, ErrorAttributeOptions.of(Include.EXCEPTION,
                Include.STACK_TRACE, Include.MESSAGE, Include.BINDING_ERRORS));
        var status = (int) errorPropertiesMap.get("status");
        var exception = this.getError(request);
        var code = "";
        var message = "";
        var trace = "";

        if (exception instanceof BusinessException) {
            var businessException = (BusinessException) exception;

            status = businessException.getStatus();
            code = businessException.getCode();
            message = exception.getMessage();
        } else {
            code = String.valueOf(status);
            try (var stringWriter = new StringWriter(); var printWriter = new PrintWriter(stringWriter)) {
                exception.printStackTrace(printWriter);
                trace = stringWriter.getBuffer().toString();
            } catch (IOException ex) {
                logger.error(ex);
            }

            if (status == 400) {
                message = "参数错误";
            } else if (status == 401) {
                message = "无权访问";
            } else if (status == 404) {
                message = "未找到";
            } else if (status == 500) {
                message = "服务内部错误";
            }
        }

        var serviceErrorLog = new ServiceErrorLog();

        serviceErrorLog.setApplicationName(applicationName);
        serviceErrorLog.setServerIp(consulRegistration.getHost());
        serviceErrorLog.setPath(StringUtils.isNotBlank(request.path()) ? request.path() : "");

        if (!request.queryParams().isEmpty()) {
            try {
                serviceErrorLog.setQueryParams(objectMapper.writeValueAsString(request.queryParams()));
            } catch (IOException ex) {
                logger.error(ex);
            }
        }

        if (StringUtils.isBlank(serviceErrorLog.getQueryParams())) {
            serviceErrorLog.setQueryParams("");
        }

        serviceErrorLog.setMessage(message);
        serviceErrorLog.setTrace(trace);
        serviceErrorLog.setLogTime(LocalDateTime.now());

        if (status != 404) {
            sendError(serviceErrorLog);
        }

        var errorMap = new HashMap<String, Object>();

        errorMap.put("code", code);
        errorMap.put("message", message);
        errorMap.put("trace", trace);

        return ServerResponse.status(HttpStatus.valueOf(status)).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(errorMap));
    }

    private void sendError(ServiceErrorLog serviceErrorLog) {
        if (!profile.endsWith("-local")) {
            try {
                var messageChannel = logStreams.outboundLogStreams();

                messageChannel.send(MessageBuilder.withPayload(serviceErrorLog)
                        .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
                        .setHeader("partitionKey", "service-error-logs").build());
            } catch (Exception ex) {
                logger.error(ex);
            }
        }
    }
}

相关文章

网友评论

      本文标题:尝鲜Spring Cloud 2020.0.0

      本文链接:https://www.haomeiwen.com/subject/kxaynktx.html