Spring Cloud 微服务架构搭建

Spring Cloud 微服务架构搭建(使用jenkins+docker自动部署)

Author:周留名
前言:由于项目框架升级,由SSM框架改为Springboot框架,然后集成Spring Cloud

1.SpringCloud简介

​ Spring Cloud 是一个相对比较新的微服务框架,2016 才推出 1.0 的 Release 版本. 但是其更新特别快,几乎每 1-2 个月就有一次更新,虽然 Spring Cloud 时间最短, 但是相比 Dubbo 等 RPC 框架, Spring Cloud 提供的全套的分布式系统解决方案。

​ Spring Cloud 为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性 Token,全居琐,Leader 选举,分布式 Session,集群状态)中快速构建的工具,使用 Spring Cloud 的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。

2.SpringCloud运行模式

在这里插入图片描述

3.创建一个eureka注册中心

这里使用idea开发,首先创建一个eureka-server项目作为注册中心创建过程不再细说,直接看配置

1.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>com.zlm</groupId>
   <artifactId>eureka-server</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>eureka-server</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.0.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.M1</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <!--docker 插件配置-->
   <build>
      <finalName>eureka</finalName>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
         <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.2.3</version> <configuration>
            <imageName>${project.artifactId}</imageName>
            <dockerDirectory>src/main/docker</dockerDirectory>
            <resources>
               <resource>
                  <targetPath>/</targetPath>
                  <directory>${project.build.directory}</directory>
                  <include>${project.build.finalName}.jar</include>
               </resource>
            </resources>
         </configuration>
         </plugin>
      </plugins>
   </build>

   <repositories>
      <repository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>
</project>

2.application.yml配置文件

server:
  port: 8761
spring:
  application:
    name: eureka-server
eureka:
  instance:
  #eureka实例主机名
    hostname: 123.207.82.109
  client:
    #不把自己注册到eureka上面
    register-with-eureka: false
    #不从eureka上获取服务
    fetch-registry: false
    #注册中心地址
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3. 启动类

package com.zlm.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @Description: Eureka注册中心
 * 1.配置Eureka基本信息
 * 2.@EnableEurekaServer启用注册中心
 */

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

   public static void main(String[] args) {
      SpringApplication.run(EurekaServerApplication.class, args);
   }
}

4.docker配置文件

docker文件存放路径为/src/main/java/docker/Dockerfile

在这里插入图片描述

FROM java:8
VOLUME /tmp
ADD eureka.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-D java.security.egd=file:/dev/./urandom","-jar","/app.jar"]

5.运行结果

这是最终部署好的运行图
在这里插入图片描述

4.创建一个Provider服务提供者

创建一个项目provider 作为服务提供者

1.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>com.zlm</groupId>
   <artifactId>provider</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>provider</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.0.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.M1</spring-cloud.version>
      <druid.version>1.1.10</druid.version>
      <mybatis.boot.starter.version>1.3.1</mybatis.boot.starter.version>
      <mysql.connector.java.version>5.1.44</mysql.connector.java.version>
      <log4j.version>1.3.8.RELEASE</log4j.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <!--数据库连接池-->
      <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid-spring-boot-starter</artifactId>
         <version>${druid.version}</version>
      </dependency>
      <!--mybatis 依赖-->
      <dependency>
         <groupId>org.mybatis.spring.boot</groupId>
         <artifactId>mybatis-spring-boot-starter</artifactId>
         <version>${mybatis.boot.starter.version}</version>
      </dependency>

      <dependency>
         <groupId>com.github.pagehelper</groupId>
         <artifactId>pagehelper-spring-boot-starter</artifactId>
         <version>1.2.5</version>
      </dependency>
      <!--mysql连接依赖-->
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>${mysql.connector.java.version}</version>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>
      <!--添加fastjson依赖-->
      <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>1.2.7</version>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
      </dependency>
   </dependencies>

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

   <build>
      <finalName>provider</finalName>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
         <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.2.3</version> <configuration>
            <imageName>${project.artifactId}</imageName>
            <dockerDirectory>src/main/docker</dockerDirectory>
            <resources>
               <resource>
                  <targetPath>/</targetPath>
                  <directory>${project.build.directory}</directory>
                  <include>${project.build.finalName}.jar</include>
               </resource>
            </resources>
         </configuration>
         </plugin>
      </plugins>
   </build>

   <repositories>
      <repository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>
</project>

2.application.yml配置文件

server:
  port: 8762
spring:
  application:
    name: provider
  datasource:
      username: ****
      password: ****
      url: jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=true
      driver-class-name: com.mysql.jdbc.Driver
      type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  # mapper 所对应接口所在位置
  mapper-locations: classpath:/mapper/*Mapper.xml
  # MyBatis mapper所对应实体类
  type-aliases-package: com.zlm.provider.pojo
  #开启驼峰命名规则
  configuration:
      map-underscore-to-camel-case: true

eureka:
  instance:
    prefer-ip-address: true
    #这里是一个大坑,如果不配置,部署的时候服务提供者与消费者必须在同一台服务器,否则无法获取服务
    #部署的服务器的ip
    ip-address: 127.0.0.1
  client:
    #注册中心地址
    service-url:
      defaultZone: http://123.207.82.109:8761/eureka/

3.启动类

package com.zlm.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Description: Provider服务提供者
 */
@SpringBootApplication
public class ProviderApplication {

   public static void main(String[] args) {
      SpringApplication.run(ProviderApplication.class, args);
   }
}

5.创建一个controller提供服务

package com.zlm.provider.controller;

import org.springframework.web.bind.annotation.*;

/**
 * @Author: 周留名
 * @Date: 2018/11/1 15:54
 * @Description
 **/
@RestController
public class ProviderController {

    @RequestMapping(value ="/getService",method = RequestMethod.GET)
    public String GetService(@RequestParam(value = "message") String message){
        return message+"获取到服务";
    }
}

6.docker配置文件

路径同上

FROM java:8
VOLUME /tmp
ADD provider.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-D java.security.egd=file:/dev/./urandom","-jar","/app.jar"]

5.创建一个Feign消费者

创建一个项目feign作为消费者

1.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>com.zlm</groupId>
   <artifactId>feign</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>feign</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.0.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.M1</spring-cloud.version>
   </properties>

   <dependencies>

      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>

      <!--Feign客户端-->
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>

      <!--熔断器-->
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      </dependency>

      <!--熔断器仪表盘监控-->
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>

   </dependencies>

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

   <build>
      <finalName>feign</finalName>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
         <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.2.3</version> <configuration>
            <imageName>${project.artifactId}</imageName>
            <dockerDirectory>src/main/docker</dockerDirectory>
            <resources>
               <resource>
                  <targetPath>/</targetPath>
                  <directory>${project.build.directory}</directory>
                  <include>${project.build.finalName}.jar</include>
               </resource>
            </resources>
         </configuration>
         </plugin>
      </plugins>
   </build>

   <repositories>
      <repository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>


</project>

2.application.yml

server:
  port: 8763
spring:
  application:
    name: feign

eureka:
  instance:
    prefer-ip-address: true
  client:
    #注册中心地址
    service-url:
      defaultZone: http://123.207.82.109:8761/eureka/
#开启熔断器
feign:
  hystrix:
    enabled: true

3.启动类

package com.zlm.feign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Description: Consumer服务消费者
 * @EnableDiscoveryClient 开启发现服务功能
 * @ENableFeignClients 标注为Feign客户端
 * @EnableHystrix 开启熔断器功能
 * @EnableHystrixDashboard 开启熔断器仪表盘监控功能
 */

@EnableHystrix
@EnableHystrixDashboard
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignApplication {

   public static void main(String[] args) {
      SpringApplication.run(FeignApplication.class, args);
   }
}

4.目录结构

在这里插入图片描述

5.获取服务

FeignController.java

package com.zlm.feign.controller;

import com.zlm.feign.service.FeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Author: 周留名
 * @Date: 2018/11/3 13:54
 * @Description
 **/
@RestController
public class FeignController {

    @Autowired
    private FeignService feignService;

    @RequestMapping(value = "/getMessage" ,method = RequestMethod.GET)
    public String GetMessage(@RequestParam String message){
        return feignService.getMessage(message);
    }


    @RequestMapping(value = "/selectAllUser.action",method = RequestMethod.GET)
    public String SelectAllUser(){
        return feignService.selectAllUser();
    }
}

FeiginService.java接口

package com.zlm.feign.service;

import com.zlm.feign.service.hystrix.FeignHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Author: 周留名
 * @Date: 2018/11/3 14:16
 * @Description @FeignClient 标注要请求的提供者服务器的application名称
 * fallback 标注熔断器类
 **/
@FeignClient(value = "provider",fallback = FeignHystrix.class)
public interface FeignService {

    @RequestMapping(value = "/getService" ,method = RequestMethod.GET)
    String getMessage(@RequestParam(value = "message") String message);

    @RequestMapping(value = "/selectAllUser.action",method = RequestMethod.GET)
    String selectAllUser();
}

6.配置熔断器

FeignHystrix.java

package com.zlm.feign.service.hystrix;

import com.zlm.feign.service.FeignService;
import org.springframework.stereotype.Component;

/**
 * @Author: 周留名
 * @Date: 2018/11/3 17:16
 * @Description 熔断器类
 **/

@Component
public class FeignHystrix implements FeignService {
    @Override
    public String getMessage(String message) {
        return message+"服务器故障请重试";
    }

    @Override
    public String selectAllUser() {
        return  "服务器故障请重试" ;
    }
}

7.配置熔断器仪表盘

HystrixDashboardConfiguration.java

package com.zlm.feign.config;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: 周留名
 * @Date: 2018/11/3 19:21
 * @Description springboot 2.x以后需要手动配置一个Servlet
 **/
@Configuration
public class HystrixDashboardConfiguration {

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

6.创建一个统一网关服务处理

创建项目Zuul作为统一网关

1.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>com.zlm</groupId>
   <artifactId>zuul</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>zuul</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.0.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.M1</spring-cloud.version>
   </properties>

   <dependencies>

      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      <dependency>
         <groupId>org.webjars</groupId>
         <artifactId>bootstrap</artifactId>
         <version>4.1.2</version>
      </dependency>
   </dependencies>

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

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

   <repositories>
      <repository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>
</project>

2.application.yml

server:
  port: 8760
spring:
  application:
    name: zuul
eureka:
  instance:
    prefer-ip-address: true
  client:
    #注册中心地址
    service-url:
      defaultZone: http://123.207.82.109:8761/eureka/
#可配置多个消费者
zuul:
  routes:
    api-a:
      path: /c/**
      serviceId: consumer
    api-b:
      path: /f/**
      serviceId: feign

3.启动类

package com.zlm.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.EnableZuulServer;
/**
 * @Description:
 * @EnableZuulProxy 开启zuul api网管统一网关处理功能
 */

@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulApplication {
   public static void main(String[] args) {
      SpringApplication.run(ZuulApplication.class, args);
   }
}

4.路由网关服务过滤

package com.zlm.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author: 周留名
 * @Date: 2018/11/4 17:22
 * @Description zuul 路由网关服务过滤
 **/

@Component
public class MyFilter extends ZuulFilter {
    private Logger logger= LoggerFactory.getLogger(getClass());
    /**
     * 配置过滤类型,有四种不同生命周期的过滤器类型
     * 1. pre:路由之前
     * 2. routing:路由之时
     * 3. post:路由之后
     * 4. error:发送错误调用
     */

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext context=RequestContext.getCurrentContext();
        HttpServletRequest request=context.getRequest();
        HttpServletResponse response = context.getResponse();
        logger.info("当前访问路径"+request.getRequestURI());
        String user = request.getParameter("user");
        if (user == null) {
            logger.warn("user is empty");
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            try {
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("user is empty");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            logger.info("OK");
        }
        return null;
    }
}

5.错误回调

package com.zlm.zuul.provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;


/**
 * @Author: 周留名
 * @Date: 2018/11/3 20:50
 * @Description 错误回调
 **/
@Component
public class FeignFallbackProvider implements FallbackProvider {
    @Override
    public String getRoute() {
        // ServiceId,如果需要所有调用都支持回退,则 return "*" 或 return null
        return "*";
        //return "feign";
    }

    /**
     * 如果请求服务失败,则返回指定的信息给调用者
     * @param route
     * @param cause
     * @return
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            /**
             * 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
             * 不应该把 api 的 404,500 等问题抛给客户端
             * 网关和 api 服务集群对于客户端来说是黑盒
             * @return
             * @throws IOException
             */
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, Object> map = new HashMap<>();
                map.put("status", 200);
                map.put("message", "无法连接,请检查您的网络");
                return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                // 和 getBody 中的内容编码一致
                headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
                return headers;
            }
        };
    }
}

6.错误路径拦截

package com.zlm.zuul.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: 周留名
 * @Date: 2018/11/4 20:09
 * @Description
 **/
@Component
public class MyInterceptor  extends HandlerInterceptorAdapter {
    private Logger logger= LoggerFactory.getLogger(getClass());
    private List<Integer> errorCodeList = Arrays.asList(404, 403, 500, 501);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (errorCodeList.contains(response.getStatus())) {
            logger.error("所访问路径出错"+request.getRequestURI());
            response.sendRedirect("/error/" + response.getStatus()+".html");
            return false;
        }
        return super.preHandle(request, response, handler);
    }
}

7.拦截器注册

package com.zlm.zuul.config;

import com.zlm.zuul.filter.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author: 周留名
 * @Date: 2018/11/5 13:28
 * @Description
 **/

@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())    //指定拦截器类
                .addPathPatterns("/**").excludePathPatterns("/error/**");
    }

    /*SpringBoot2.0后必须配置静态资源 否则会被拦截器拦截*/
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

7.项目部署

ps:这里只把注册中心和服务提供者部署到了服务器,其他项目大致相同

1.准备工作:

1.docker的安装

2.jenkins服务的搭建

3.安装git

4.安装maven

5.jdk

2.jenkins任务配置

git仓库以及存放位置配置

/home/ubuntu/java/jenkins/springcloud/

执行shell配置

在这里插入图片描述

3.shell文件编写

cloud.sh文件

#! /bin/bash

docker stop eureka-server
docker rm eureka-server
docker rmi eureka-server
cd /home/ubuntu/java/jenkins/springcloud/eureka-server/
mvn clean package -Ptest -Dmaven.test.skip=true docker:build
docker run -p 8761:8761 --name eureka-server -d eureka-server

其他项目部署于此步骤相同,不再废话

8.总结

需要注意的地方

1.provider配置

eureka:
  instance:
    prefer-ip-address: true
    #这里是一个大坑,如果不配置,部署的时候服务提供者与消费者必须在同一台服务器,否则无法获取服务
    #部署的服务器的ip
    ip-address: 123.207.82.109
  client:
    #注册中心地址
    service-url:
      defaultZone: http://123.207.82.109:8761/eureka/

2.docker配置

<!--docker 插件配置-->
   <build>
      <finalName>eureka</finalName>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
         <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.2.3</version> <configuration>
            <imageName>${project.artifactId}</imageName>
            <dockerDirectory>src/main/docker</dockerDirectory>
            <resources>
               <resource>
                  <targetPath>/</targetPath>
                  <directory>${project.build.directory}</directory>
                  <include>${project.build.finalName}.jar</include>
               </resource>
            </resources>
         </configuration>
         </plugin>
      </plugins>
   </build>

3.Dockerfile文件编写

VOLUME /tmp
ADD provider.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-D java.security.egd=file:/dev/./urandom","-jar","/app.jar"]

猜你喜欢

转载自blog.csdn.net/qq_37918553/article/details/83796279