spring cloud&ribbon应用植入
简介
随着微服务普及,懂得微服务变得越来越重要,也是java程序员的必备基础,个人为了学习和了解微服务的负载均衡ribbon的实现原理和feignClient基础知识,针对性搭建了基础微服务架构并后面一章节简单介绍微服务符合发现服务的源码,同时介绍一下开发技巧。
应用总览
模块总览
- 注册中心eureka-server
- 用户中心user-center
- 用户中心提供的api user-center
- 前端访问调用api admin-client-api
如下图:
技术栈
- maven 构建工具
- IntelliJ IDEA 开发工具
- spring boot 基础框架
- spring cloud rest微服务体系
- spring cloud feign 客户端调用
- ribbon 负载均衡
这里搭建是居于上一章节工程初始化,使用maven的模块化开发讲解。上一次工程源码(此步走可忽略,根据自己需要初始化)
注册中心eureka-server
服务注册中心主要提供发现服务功能,还有监听服务运行是否健康等情况
pom配置
这里使用spring security作为验证注册。配置如下:
<?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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<properties>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<eureka-server.version>2.2.6.RELEASE</eureka-server.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>${eureka-server.version}</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>
<configuration>
<mainClass>com.lgh.server.ServerApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
bootstrap配置
spring:
application:
name: eureka-server
cloud:
config:
uri: http://localhost:8888/eureka/
application配置
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
waitTimeInMsWhenSyncEmpty: 0
spring:
security:
user:
name: admin
password: admin123456
启动类
在启动类中添加@EnableEurekaServer,作为注册中心服务器启动
@SpringBootApplication
@EnableEurekaServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
在上面配置完后并未完事,因为我们启动了spring security配置,这是security会防止跨站访问,我们需要配置security的跨域访问权限,否则eureka客户端将无法注册进来。
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
super.configure(http);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/favicon.ico");
super.configure(web);
}
}
接下来我们启动main方法访问http://localhost:8761/ ,eureka服务器讲启动成功,如图
用户中心user-center
pom配置
这里因为是上一章节配置文件比较多,所以比较负责,简单项目接入只需要接入如下引入即可:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
以及添加cloud管理
<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>
application配置
eureka:
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 2
preferIpAddress: true
client:
serviceUrl:
defaultZone: http://admin:[email protected]:8761/eureka/
启动项目
在你的启动项目添加如下注解
@EnableFeignClients
@EnableEurekaClient
启动项目后查看eureka服务器是否已经注册上
用户中心提供的api user-center
用户中心api主要提供feignClient给外部调用的jar包,这里只是简单描述,一个登录接口服务,一个验证登录服务,具体请查看后面源码:
@FeignClient(name = ServerConfig.USER_CENTER, path = "/login")
public interface ILogonClient {
@PostMapping("/sign")
LogonRepDTO login(@RequestBody LogonReqDTO logonReqDTO);
@GetMapping("/verify")
LogonRepDTO verify(@RequestParam("token") String token);
}
访问调用api admin-client-api
环境搭建和用户中心一致,不做重复讲解,这里主要讲解如何调用,针对前面文章讲解使用security验证登录,
spring获取feign ApplicationUtil.getBean(ILogonClient.class),如下:
public class MyAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
filterChain.doFilter(request, response);
} else {
ILogonClient iLogonClient = ApplicationUtil.getBean(ILogonClient.class);
LogonRepDTO logonRepDTO = iLogonClient.verify(token);
if (logonRepDTO == null) {
ObjectMapper objectMapper = ApplicationUtil.getBean(ObjectMapper.class);
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(objectMapper.writeValueAsString(CommonResult.deny()));
return;
} else {
UserDetail userDetail = new UserDetail();
userDetail.setId(logonRepDTO.getId());
userDetail.setName(logonRepDTO.getUserName());
List<MySimpleGrantedAuthority> roles = new ArrayList<>();
if (logonRepDTO.getUserResources() != null) {
roles = logonRepDTO.getUserResources().stream()
.map(ResourceDomain::getResourceCode)
.map(MySimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
MyAuthentication myAuthentication = new MyAuthentication(userDetail, roles);
SecurityContextHolder.getContext().setAuthentication(myAuthentication);
filterChain.doFilter(request, response);
}
}
}
}
自动注入形式调用,如登录访问接口
@Api(tags = "登录服务")
@RestController
@RequestMapping("/login")
@Validated
public class LogonController {
@Autowired
private ILogonClient iLogonClient;
@ApiOperation("登录服务接口")
@PostMapping("/sign")
@Valid
public IResult<LogonRepDTO> login(@RequestBody LogonReqDTO logonReqDTO) {
LogonRepDTO logonRepDTO = iLogonClient.login(logonReqDTO);
return CommonResult.successData(logonRepDTO);
}
@GetMapping("/testFilter")
public String testFilter() {
return "available!";
}
}
总结
这里总结自己在搭建过程中问题总结
- spring cloud和boot版本不一致问题,以及解决版本冲突方式,我们可以通过找到对应匹配版本或者通过maven的exclusions
- eurake server注册中心没法注册,因为开启了security跨站拦截,即使设置了用户名密码也无法访问,## http://admin:admin123456@127.0.0.1:8761/eureka/ ,需要设置http.csrf().disable(),在解决过程中可以通过去掉security看是否是security问题
- feign可指定IP访问,以便开发链条或者百名单形式配置
eureka.client.enabled = false
user-center.ribbon.listOfServers: localhost:8085 # 黑体是feign的name实例名 - 更多问题查看FeignClient如何寻址
参看文献
【1】HowToDoInJava
【2】feignClient