springboot+kotlin+springcloud+java+grade+maven混编?

springboot + maven + java vs springboot + gradle + kotlin

快速搭建:https://start.spring.io/

springclould:netflix:

java:

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.fly</groupId>
<artifactId>springboot01</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--通用mapper
已包含jdbc mybatis
-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

kotlin:

build.gradle:

buildscript {
   ext {
      kotlinVersion = '1.2.71'
      springBootVersion = '2.1.1.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
     classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
      classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
      classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
   }
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
   kotlinOptions {
      freeCompilerArgs = ["-Xjsr305=strict"]
      jvmTarget = "1.8"
   }
}
compileTestKotlin {
   kotlinOptions {
      freeCompilerArgs = ["-Xjsr305=strict"]
      jvmTarget = "1.8"
   }
}
repositories {
   mavenCentral()
}
dependencies {
   implementation('org.springframework.boot:spring-boot-starter-web')
   implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
   implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
   implementation("org.jetbrains.kotlin:kotlin-reflect")
   implementation("tk.mybatis:mapper-spring-boot-starter:2.0.3")
   implementation("mysql:mysql-connector-java:5.1.6")
   testImplementation('org.springframework.boot:spring-boot-starter-test')
}

java:8088

kotlin:8089

application.yml:

server:
  port: 8088
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatisdemo
    username: root
    password: root
    hikari:   # jdbc默认连接池
      maximum-pool-size: 20
      minimum-idle: 10
mybatis:
  type-aliases-package: com.fly.pojo
logging:
  level:
    com.fly.service: error

App:

java:

@SpringBootApplication
@MapperScan("com.fly.mapper")
public class App {
public static void main(String[] args){
SpringApplication.run(App.class,args);
}
} kotlin: @SpringBootApplication
@MapperScan("com.fly.mapper")
class Application{
@Bean
fun restTemplate():RestTemplate = RestTemplate()
} fun main(args: Array<String>) {
// SpringApplication.run(Application::class.java,*args)
runApplication<Application>(*args)
}
pojo.User:

java:

@Data
@Table(name = "user")
public class User {
@Id
@KeySql(useGeneratedKeys = true)//插入的表以自增列为主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略
@Column(name = "id")
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}

kotlin:

@Table(name = "user")
data class User(
    @Id
    @KeySql(useGeneratedKeys = true)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    var id: Int? = null,
    var username: String? = null,
    var birthday: Date? = null,
    var sex: String? = null,
    var address: String? = null
)

UserMapper:

java:

public interface UserMapper extends Mapper<User> {
}

kotlin:

interface UserMapper:Mapper<User>

UserService:

java:

@Service
public class UserService {
@Resource
private UserMapper userMapper; public List<User> selectAll(){
return userMapper.selectAll();
} @Transactional
public void insert(User user){
userMapper.insert(user);
}
}

kotlin:

@Service
class UserService {
    @Resource
    lateinit var userMapper:UserMapper

    fun selectAll():List<User> = userMapper.selectAll()

@Transactional
    fun insert(user: User) = userMapper.insert(user)
}

UserController:

java:

@RestController
public class UserController {
@Resource
private UserMapper userMapper; private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
} @GetMapping("/")
public List<User> selectAll(){
return userService.selectAll();
}
@GetMapping("/{id}")
public User selectById(@PathVariable("id")int id){
return userMapper.selectByPrimaryKey(id);
}
}

kotlin:

@RestController
class UserController {

@Autowired
    lateinit var userService: UserService

@Autowired
    lateinit var restTemplate:RestTemplate

@GetMapping
    fun selectAll(): List<User> = userService.selectAll()

@GetMapping("/{id}")
    fun httpSelectAll(@PathVariable("id") id:Int):User?{
        return restTemplate.getForObject("http://localhost:8088/"+id, User::class.java)
    }

}

MyInterceptor:

java:

/**
* 拦截器
*/
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
// private Logger log = LoggerFactory.getLogger(MyInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle......");
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle.....");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion.....");
}
}

kotlin:

class MyInterceptor :HandlerInterceptor{
    var log:Logger = LoggerFactory.getLogger(MyInterceptor::class.java)
    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        log.info("preHandle......")
        return true
    }

override fun postHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any, modelAndView: ModelAndView?) {
        log.info("postHandle......")
    }

override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) {
        log.info("afterCompletion......")
    }
}

MvcConfig:

java:

/**
* 注册拦截器
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器,添加拦截路径
registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
}
}

kotlin:

@Configuration
class MvcConfig :WebMvcConfigurer{
    @Bean
    fun myInterceptor():MyInterceptor = MyInterceptor()

override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(myInterceptor()).addPathPatterns("/**")
    }
}

测试:

java:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)//()内容可省略
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void test() {
List<User> list = userService.selectAll();
for (User user : list) {
System.out.println(user);
}
}
@Test
public void test1(){
User user = new User();
user.setUsername("测试a");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("A");
userService.insert(user);
}
}

kotlin:

@RunWith(SpringRunner::class)
@SpringBootTest(classes = arrayOf(Application::class))
class UserServiceTest {
    @Autowired
    lateinit var userService:UserService
    @Test
    fun test(){
        val list:List<User> = userService.selectAll()
        for (user in list) {
            println(user)
        }
    }

@Test
    fun test1(){
        val user = User()
        user.username = "Kotlin111"
        user.address = "K"
        user.sex = "1"
        user.birthday = Date()
        userService.insert(user)
    }
}

netflix:

Eureka:注册中心

Zuul:服务网关

Ribbon:负载均衡

Feign:服务调用

Hystix:熔断器

Eureka:注册中心

grade+java搭建eureka服务,客户端分别为上面的java+kotlin

eureka服务端:

build.gradle:

buildscript {
    ext {
        springBootVersion = '2.1.1.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.fly'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
}

ext['springCloudVersion'] = 'Greenwich.RC2'

dependencies {
    implementation('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

application.yml:

server:
port: 8761 # 默认8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false # 注册自己的信息到EurekaServer
fetch-registry: false # 拉取其它服务的信息
service-url:
defaultZone: http://127.0.0.1:${server.port}/eureka
server:
eviction-interval-timer-in-ms: 60000 # 扫描失效服务的间隔时间 失效剔除 单位是毫秒,生成环境不要修改
enable-self-preservation: false # 关闭自我保护 默认为true

EurekaApplication:

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

客户端:

java:

pom.xml:

<!--Eureka客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
</dependency>

application.yml:

server:
  port: 8088

spring:
  application:
      name: springboot01
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatisdemo
    username: root
    password: root
    hikari:   # jdbc默认连接池
      maximum-pool-size: 20
      minimum-idle: 10

mybatis:
  type-aliases-package: com.fly.pojo
logging:
  level:
    com.fly.service: error
eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:8761/eureka
    registry-fetch-interval-seconds: 30 # 默认值 获取服务列表
  instance:
    prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
    # 修改服务续约的行为
    lease-expiration-duration-in-seconds: 90 # 服务失效时间,默认值90秒
    lease-renewal-interval-in-seconds: 30 # 服务续约(renew)的间隔,默认为30秒
    instance-id: ${spring.application.name} + ${server.port} # 默认显示的信息${hostname}:${spring.application.name}:${server.port}

App部分:

@SpringBootApplication
//@EnableEurekaClient //开启eureka客户端
@EnableDiscoveryClient //客户端,支持多种
@MapperScan("com.fly.mapper")
public class App {

服务的消费方:

build.gradle:

implementation('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:2.0.2.RELEASE')

application.yml:

server:
  port: 8089
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatisdemo
    username: root
    password: root
  application:
    name: demo
  main:
    allow-bean-definition-overriding: true # 同名bean覆盖
mybatis:
  type-aliases-package: com.fly.pojo
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka
    registry-fetch-interval-seconds: 30 # 默认值 获取服务列表
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

Application.kt:

@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.fly.mapper")
class Application{
    @Bean
    fun restTemplate():RestTemplate = RestTemplate()
}

fun main(args: Array<String>) {
//    SpringApplication.run(Application::class.java,*args)
    runApplication<Application>(*args)
}

UserService:

@Autowired
lateinit var restTemplate: RestTemplate
@Autowired
lateinit var discoveryClient:DiscoveryClient

fun queryUserById(id: Int):User?{
    // 根据服务名称,获取服务实例
    // 因为只有一个UserService,因此我们直接get(0)获取
    val instances = discoveryClient.getInstances("springboot01").get(0)
    // 获取ip和端口信息
    val url:String = "http://"+instances.host + ":" + instances.port +"/"+ id
    return restTemplate.getForObject(url, User::class.java)
}

UserController:

@GetMapping("/user/{id}")
fun eurekaQueryUserById(@PathVariable("id") id: Int):User?{
    return userService.queryUserById(id)
}

Ribbon:负载均衡

负载均衡:

spring-cloud 的 netfix已经包含,无需再导入

org.springframework.cloud:spring-cloud-starter-netflix-ribbon

Application.kt:

@Bean
@LoadBalanced // 开启负载均衡
fun restTemplate():RestTemplate = RestTemplate()

UserService:

//    负载均衡 使用 @LoadBalanced
    fun queryUserById(id: Int):User?{
        // url直接写服务名,LoadBalancerInterceptor会根据服务名获取服务实例的ip与端口
        val url = "http://springboot01/"
        return restTemplate.getForObject(url+id, User::class.java)
    }

重试机制

build.gradle:

// 重试机制
implementation('org.springframework.retry:spring-retry:1.2.2.RELEASE')

application.yml部分:

server:
  port: 8089
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mybatisdemo
    username: root
    password: root
  application:
    name: demo
  main:
    allow-bean-definition-overriding: true # 同名bean覆盖
  cloud:
    loadbalancer:
      retry:
        enabled: true # 开启Spring Cloud的重试功能
springboot01: # 服务名称 负载均衡规则的配置入口
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 默认轮训 值为IRule的实现类
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数

Hystix:熔断器

熔断器:

build.gradle:

//熔断器
implementation('org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.0.2.RELEASE')

Application.kt:

//@SpringBootApplication
//@EnableCircuitBreaker //熔断
//@EnableDiscoveryClient //注册客户端
//@EnableEurekaClient

@SpringCloudApplication //包含上面前3

UserService部分:

@Service
//@DefaultProperties(defaultFallback = "queryUserByIdFallBack")
class UserService {
    @Autowired
    lateinit var restTemplate: RestTemplate
//    负载均衡 使用 @LoadBalanced
    @HystrixCommand(fallbackMethod = "queryUserByIdFallBack") //失败回滚 默认是1000毫秒

//    @HystrixCommand(commandProperties =
//        [HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")] //超时时间
//    )
//    @HystrixCommand
    fun queryUserById(id: Int):User?{
        val begin:Long = System.currentTimeMillis()
        // url直接写服务名,LoadBalancerInterceptor会根据服务名获取服务实例的ip与端口
        val url = "http://springboot01/"
        val user:User? = restTemplate.getForObject(url+id, User::class.java)
        val end:Long = System.currentTimeMillis()
        val t:Long = end - begin
        println("访问时间:$t")
        return user
    }
    fun queryUserByIdFallBack():User?{
        val user = User()
        user.username = "服务器太拥挤了!!!"
        return user
    }

fun queryUserByIdFallBack(id: Int):User?{
        val user = User()
        user.username = "服务器太拥挤了!!!"
        return user
    }

配置文件方式配置:

application.yml:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000 # 设置hystrix的超时时间为3000ms

服务提供方模拟超时:

@GetMapping("/")
public List<User> selectAll(){
    return userService.selectAll();
}
@GetMapping("/{id}")
public User selectById(@PathVariable("id")int id) throws InterruptedException {
    Thread.sleep(2000L); //模拟超时
    return userMapper.selectByPrimaryKey(id);
}

断路器配置:

@HystrixCommand(commandProperties =
    [
        //具体参数位置 HystrixCommandProperties.java
        /* 状态机的三种状态
        *  Closed:关闭状态(断路器关闭),所有请求都正常访问
        *  Open:打开状态(断路器打开),所有请求都被降级,hystix会对请求情况进行计数,当失败的百分比达到阀值
        *       ,则触发熔断,断路器完全关闭
        *  Half Open:半开状态,Closed状态不是永久的,关闭后会进入休眠,随后断路器自动进入半开状态,
        *       此时会释放部分请求通过。若请求是健康的,则会完全打开断路器,否则保持关闭,再进行休眠计时
        *
        * */
        HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"), //执行超时时间 默认1000
        HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 触发熔断器的最小请求次数 默认20
        HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 休眠时长 默认5000毫秒
        HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50") //触发熔断的失败请求最小占比 默认50%
    ] //超时时间
)

Feign:服务调用

Feign:(伪装

build.gradle:

// feign
implementation('org.springframework.cloud:spring-cloud-starter-openfeign:2.0.2.RELEASE')

Application.kt:

@EnableFeignClients // 开启Feign功能

feign,熔断器设置:

UserFeignClient:

@FeignClient(value = "springboot01",fallback = UserFeignClientFallback::class,configuration = [FeignConfig::class])
interface UserFeignClient {
    @GetMapping("/{id}")
    fun feignQueryUserById(@PathVariable("id")id:Int): User
}

UserFeignClientFallback:

@Component
class UserFeignClientFallback:UserFeignClient {
    override fun feignQueryUserById(id: Int): User {
        val user = User()
        user.username = "未知用户???"
        return user
    }
}

UserController:

@Resource
lateinit var userFeignClient: UserFeignClient
@GetMapping("/feignUser/{id}")
fun feignQueryUserById(@PathVariable("id") id: Int):User{
    return userFeignClient.feignQueryUserById(id)
}

负载均衡,熔断器,日志设置:

application.yml:

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能 默认关闭

ribbon: # feign的ribbon的配置 也可以使用上面ribbon的配置方式
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 3000 #  通信超时时间(ms)
#  OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
#  MaxAutoRetriesNextServer: 1 # 同一服务不同实例的重试次数
#  MaxAutoRetries: 1 # 同一实例的重试次数

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000 # 设置hystrix的超时时间为 ms

logging: # 日志级别
  level:
    com.fly: debug

请求压缩

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型 默认
      min-request-size: 2048 # 设置触发压缩的大小下限 默认
    response:
      enabled: true # 开启响应压缩

Zuul:服务网关

面向服务:

pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
<properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
    <!--Eureka客户端依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

ZuulApplication:

@SpringBootApplication
@EnableZuulProxy //开启Zuul的功能
@EnableDiscoveryClient
public class ZuulApplication {

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

}

application.yml:

server:
  port: 9901
spring:
  application:
    name: zuul
#zuul:
#  routes:
#    springboot01: # 路由id,随意写 将 /user/**开头的请求,代理到http://127.0.0.1:8087
#      path: /user/** # 这里是映射路径
##      url: http://127.0.0.1:8087  # 映射路径对应的实际url地址
#      serviceId: springboot01 # 指定服务名称 ,会利用Ribbon进行负载均衡访问
#  简化的路由配置
#zuul:
#  routes:
#    springboot01: springboot01/** # 服务名与映射地址相同可以省略

#  路由前缀
zuul:
#  prefix: /api # 添加路由前缀
  routes:
    springboot01:
      path: /user/**
      serviceId: springboot01
  retryable: true # 重试 默认false

#  ignored-services: # 忽略的服务
#    - springboot02
#    - springboot03

# 熔断
ribbon: # ribbon的配置 详见 AbstractRibbonCommand.java
  ConnectTimeout: 250 # 连接超时时间(ms) 默认1000
  ReadTimeout: 2000 #  通信超时时间(ms) 默认1000
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 1 # 同一服务不同实例的重试次数 默认1
  MaxAutoRetries: 0 # 同一实例的重试次数 默认0

# 负载均衡
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000 # 熔断超时时长:6000ms > (ReadTimeout+ConnectTimeout)*2,ribbon默认重试1次
# ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)
#   (250 + 2000)* (0+1)*(1+1)

eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:8761/eureka
    registry-fetch-interval-seconds: 30 # 默认值 获取服务列表
  instance:
    prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

自定义过滤器

/**
 * 自定义过滤器
 */
@Component
public class LoginFilter extends ZuulFilter {
    @Override
    public String filterType() {//返回字符串,代表过滤器的类型
        /**
         * - pre:请求在被路由之前执行
         * - routing:在路由请求时调用
         * - post:在routing和errror过滤器之后调用
         * - error:处理请求时发生错误调用
         */
//        return "pre";
        return FilterConstants.PRE_TYPE;
    }

@Override
    public int filterOrder() {//通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;//4
    }

@Override
    public boolean shouldFilter() {//返回一个`Boolean`值,判断该过滤器是否需要执行。返回true执行,返回false不执行
        return true;
    }

@Override
    public Object run() throws ZuulException {//过滤器的具体业务逻辑
        // 获取Zuul提供的请求上下文对象
        RequestContext context = RequestContext.getCurrentContext();
        // 从上下文中获取request对象
        HttpServletRequest request = context.getRequest();
        String token = request.getParameter("user-token");
        //判断是否存在
        if (StringUtils.isBlank(token)){
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.FORBIDDEN.value());//403
        }
        return null;
    }
}

上一篇:Python类继承,方法重写及私有方法


下一篇:Mybatis框架入门