新建Spring Boot項目
怎么新建Spring Boot項目這里不再具體贅述,不會的可以翻看下之前的博客或者直接百度。這里直接貼出對應的pom文件。
pom依賴如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lifengdi</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
由於是網關項目,所以不需要spring-boot-starter-web
相關的依賴。
配置文件如下:
server:
port: 8080
spring:
application:
name: spring-cloud-gateway-demo
cloud:
gateway:
discovery:
locator:
enabled: true #啟用路由訪問
routes:
- id: path_route
# 指定域名
uri: http://localhost:8081
predicates:
- Path=/jar/**
filters:
# 熔斷配置
- name: Hystrix
args:
name: default
fallbackUri: forward:/fallback
- id: path_route2
# 指定域名
uri: http://localhost:8082
predicates:
- Path=/war/**
filters:
# 熔斷配置
- name: Hystrix
args:
name: hystrix1
fallbackUri: forward:/fallback
mvc:
throw-exception-if-no-handler-found: true
# 默認熔斷超時時間30s
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
hystrix1:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
熔斷(接口或者項目)
熔斷相關jar包如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
默認的熔斷回調接口:
package com.lifengdi.gateway.hystrix;
import com.lifengdi.gateway.exception.BaseException;
import com.lifengdi.gateway.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: Li Fengdi
* @date: 2020-03-18 16:35
*/
@RestController
@Slf4j
public class DefaultHystrixController {
@RequestMapping("/fallback")
public ResponseResult<Object> fallback(){
log.error("觸發熔斷......");
return ResponseResult.fail(BaseException.DEFAULT_HYSTRIX.build());
}
}
具體配置文件說明如下:
routes:
- id: path_route
# 指定域名
uri: http://localhost:8081
predicates:
- Path=/jar/**
filters:
# 熔斷配置
- name: Hystrix
args:
name: default
fallbackUri: forward:/fallback
- id: path_route2
# 指定域名
uri: http://localhost:8082
predicates:
- Path=/war/**
filters:
# 熔斷配置
- name: Hystrix
args:
name: hystrix1
fallbackUri: forward:/fallback
mvc:
throw-exception-if-no-handler-found: true
# 默認熔斷超時時間30s
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
hystrix1:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
default
、hystrix1
為自定義的參數,可以配置多個熔斷策略,不同的接口、服務可以單獨配置對應的超時時間,不需要額外的進行開發,不過需要增加額外的配置文件。
全局session共享
依賴jar包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
相關yml配置:
spring:
redis:
database: 0
host: localhost
port: 6379
password: 123456
lettuce:
pool:
max-active: 300
max-idle: 8
max-wait: -1ms
min-idle: 0
session:
store-type: redis
spring.session.store-type
Spring默認就是redis實現的,也有其他的,配置不同罷了。
增加代碼如下:
權限相關,這里默認全部放行:
package com.lifengdi.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity serverHttpSecurity)
throws Exception {
serverHttpSecurity
.csrf().disable()
.authorizeExchange().pathMatchers("/**").permitAll()
.anyExchange()
.authenticated();
return serverHttpSecurity.build();
}
}
session相關:
package com.lifengdi.gateway.config;
import com.lifengdi.gateway.resolver.MyCookieWebSessionIdResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseCookie;
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
import org.springframework.web.server.session.CookieWebSessionIdResolver;
import org.springframework.web.server.session.WebSessionIdResolver;
import java.util.function.Consumer;
@Configuration
@EnableRedisWebSession(maxInactiveIntervalInSeconds = 10*60*60, redisNamespace = "my:spring:session")
public class WebSessionConfig {
@Bean
public WebSessionIdResolver webSessionIdResolver() {
CookieWebSessionIdResolver resolver = new MyCookieWebSessionIdResolver();
resolver.setCookieName("SESSIONID");
Consumer<ResponseCookie.ResponseCookieBuilder> consumer = responseCookieBuilder -> {
responseCookieBuilder.path("/");
};
resolver.addCookieInitializer(consumer);
return resolver;
}
}
注意這里使用的是@EnableRedisWebSession
注解,而不是@EnableRedisHttpSession
,這個是和zuul不一樣的地方。
用zuul做網關的時候,直接使用@EnableRedisHttpSession
在配置里面就可以通過redis共享session信息
Spring同時提供了@EnableRedisWebSession
來對WebFlux的支持。
值得一提的是這兩個注解內部實現並不相同,需要自定義的配置也不一樣。
這里自定義cookieName、path等是自定義了webSessionIdResolver
來實現的,而不是cookieSerializer
。如果使用cookieSerializer
的話,對@EnableRedisWebSession
來說是不起作用的。這個坑之前坑了好半天!
MyCookieWebSessionIdResolver代碼如下:
package com.lifengdi.gateway.resolver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.session.CookieWebSessionIdResolver;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 自定義WebSessionId解析器,以兼容{@link org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession}
* <p>
* 使用EnableRedisHttpSession時{@link DefaultCookieSerializer}中useBase64Encoding默認為true,將cookie中的sessionId使用base64
* 加密,但是如果使用{@link org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession},默認
* 的解析器沒有將sessionId解密,導致獲取不到正確的session
* </p>
*
* @author: Li Fengdi
* @date: 2020/3/16 15:41
*/
@Slf4j
public class MyCookieWebSessionIdResolver extends CookieWebSessionIdResolver {
@Override
public List<String> resolveSessionIds(ServerWebExchange exchange) {
MultiValueMap<String, HttpCookie> cookieMap = exchange.getRequest().getCookies();
List<HttpCookie> cookies = cookieMap.get(getCookieName());
if (cookies == null) {
return Collections.emptyList();
}
return cookies.stream().map(HttpCookie::getValue).map(this::base64Decode).collect(Collectors.toList());
}
/**
* base64解碼
*
* @param base64Value base64Value
* @return 解碼后的字符串
*/
private String base64Decode(String base64Value) {
try {
byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);
return new String(decodedCookieBytes);
} catch (Exception ex) {
log.debug("Unable to Base64 decode value: " + base64Value);
return null;
}
}
}
其實這段代碼本就是參考了cookieSerializer
中的代碼來實現的。
如果指定了useBase64Encoding為false,即不加密sessionId,那么就不需要這一段代碼了。
代碼已上傳到git上,需要的可以去看看。
git代碼地址:https://github.com/lifengdi/spring-cloud-gateway-demo