SpringCloud是Spring旗下的项目之一,官网地址:http://projects.spring.io/spring-cloud/
Spring最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。
SpringCloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:
netflix
首先先引入需要的依赖:
pom文件:
<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.0modelVersion>
<groupId>cn.itcast.demogroupId>
<artifactId>cloud-demoartifactId>
<version>1.0.0-SNAPSHOTversion>
<modules>
<module>user-servicemodule>
<module>consumer-demomodule>
<module>eureka-servicemodule>
<module>gatewaymodule>
modules>
<packaging>pompackaging>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR1spring-cloud.version>
<mapper.starter.version>2.0.3mapper.starter.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>${mapper.starter.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.32version>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
上面是所需要的全部依赖
创建聚合工程
<packaging>pompackaging>
各种版本
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR1spring-cloud.version>
<mapper.starter.version>2.0.3mapper.starter.version>
properties>
提供SpringBoot的Maven插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
在创建了父工程之后我们在这里列举一下我们在这个demo中会创建的微服务:
1.user-service
2.consumer-demo
3.eureka-service
4.gageway
上面这四个就是这次demo案例中我们要学习的4个微服务,我们将通过他们来了解SpringCloud。
其中user-service 是服务的提供者,consumer-demo是服务的调用者,eureka-service是一个注册中心,gageway是网关提供一些保护机制。
这是一个提供服务的微服务。
1.右键单击父工程cloud-demo =>选择New=>选择Model:
2.然后进行工程的创建:
创建一个Maven工程,点击Next
写名称,点击Next
修改一下名称,点击Finish
在pom文件中引入需要的依赖:
<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>
<artifactId>cloud-demoartifactId>
<groupId>cn.itcast.demogroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>user-serviceartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
project>
在user-service => src => main => java 中创建包cn.itcast,并在其中创建UserApplication类
在UserApplication中编写代码:
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;
@EnableDiscoveryClient//让这个服务被注册中心知道
@SpringBootApplication
@MapperScan("cn.itcast.user.mapper")//配置要扫描的mapper
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class);//启动的方法
}
}
在user-service => src => main => java =>cn.itcast 中创建包user,在user包下创建mapper包,在mapper包中创建接口UserMapper。
注意: 这里的UserMapper接口所在包一定要与启动类中扫描的路径相同。
因为使用了通用Mapper因此接口代码如下:
package cn.itcast.user.mapper;
import cn.itcast.user.pojo.User;
import tk.mybatis.mapper.common.Mapper;//注意引用的包
public interface UserMapper extends Mapper<User> {
}
在user-service => src => main => java => cn.itcast => user 中创建pojo包,在pojo包中创建类User。
在实体类中编写代码:
package cn.itcast.user.pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Table(name = "db_user")//连接的数据库中的表的名字
@Data//使用lombok插件,因此不需要写get/set等方法
public class User {
@Id//指定主键
@KeySql(useGeneratedKeys = true)//主键是否自增
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
在user-service => src => main => java => cn.itcast => user 中创建service包,在service包中创建类UserService。
编写代码:
package cn.itcast.user.service;
import cn.itcast.user.mapper.UserMapper;
import cn.itcast.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service//让Spring知道它
public class UserService {
@Autowired//自动注入UserMapper
private UserMapper userMapper;
public User queryById(Integer id){
/* try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
return userMapper.selectByPrimaryKey(id);//调用通用Mapper中方法根据主键查询
}
}
在user-service => src => main => java => cn.itcast => user 中创建web包,在web包中创建类UserController。
编写代码:
package cn.itcast.user.web;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
/*
@RestController注解,相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
*/
@RequestMapping("user")//表示类中的所有响应请求的方法都是以该地址作为父路径
public class UserController {
@Autowired//自动注入UserService
private UserService userService;
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Integer id){
/*
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable("xxx") 绑定到操作方法的入参中。
*/
return userService.queryById(id);//调用UserService中方法
}
}
在user-service => src => main => resources 中创建application.yml
编写配置:
#配置端口
server:
port: 8081
#配置扫描包
mybatis:
type-aliases-package: cn.itcast.user.pojo
#配置数据库链接
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis
username: root
password: abc
#配置在eureka中服务名
application:
name: user-service
#配置eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
#配置全局的超时时长
#hystrix:
#command:
#default:
#execution:
#isolation:
#thread:
#timeoutInMilliseconds: 3000
注意: 一定要注意编写规范,注意空格
这是一个调用服务的微服务
创建方法同创建 user-service,在cloud-demo下 New 一个 Module 选择Maven工程,输入名称。
在pom中引入依赖:(注意是consumer-demo这个微服务的pom文件)
<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>
<artifactId>cloud-demoartifactId>
<groupId>cn.itcast.demogroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>consumer-demoartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
<version>2.0.1.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>
project>
在consumer-demo => src => main => java 中创建包cn.itcast,并在其中创建ConsumerApplication类
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication
@SpringCloudApplication//是上面三个注解的集合,需要引入上面三个注解的对应依赖
@EnableFeignClients
public class ConsumerApplication {
//在使用Feign之后可以不用写了,使用之前需要写
// @Bean
// //负载均衡注解,加在restTemplate
// @LoadBalanced
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
在包 cn.itcast 中创建包 consumer 并在其中创建pojo包,然后在pojo包中创建User实体类。
和user-service有一些区别:
package cn.itcast.consumer.pojo;
import lombok.Data;
import java.util.Date;
@Data
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
在包 consumer 中创建web包,然后在web包中创建ConsumerController类。
package cn.itcast.consumer.web;
import cn.itcast.consumer.client.UserClient;
import cn.itcast.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("consumer")
//@DefaultProperties(defaultFallback = "queryByIdFallback")
public class ConsumerController {
/* @Autowired
private RestTemplate restTemplate;
*/
/* @Autowired
private RibbonLoadBalancerClient client;*/
//远程调用,也是最终形态
@Autowired
private UserClient userClient;
@GetMapping("{id}")
public User queryById(@PathVariable("id") Integer id) {
return userClient.queryById(id);
}
// @GetMapping("{id}")
//开启服务降级,设置熔断或者其他的
// @HystrixCommand
/*(commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
})*/
//设置超时时长(commandProperties =
// {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
// })
//(fallbackMethod = "queryByIdFallback")
//两个方法的返回值类型和参数列表必须完全相同
/* public String queryById(@PathVariable("id") Integer id) {
if (id % 2 == 0) {
throw new RuntimeException("");
}
String url = "http://user-service/user/" + id;
String user = restTemplate.getForObject(url, String.class);
return user;
}*/
/* public String queryByIdFallback(Integer id) {
return "服务器拥挤";
}*/
/* public String queryByIdFallback() {
return "服务器拥挤";
}*/
/* @GetMapping("{id}")
public User queryById(@PathVariable("id") Integer id) {
//根据服务ID获取实例
// List instances = discoveryClient.getInstances("user-service");
//从实例中取出ip和端口
// ServiceInstance serviceInstance = instances.get(0);
//默认轮询
*/ /*ServiceInstance serviceInstance = client.choose("user-service");
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;*//*
//使用负载均衡之后
String url = "http://user-service/user/" + id;
User user = restTemplate.getForObject(url, User.class);
return user;
}*/
}
注意: 这里面注释的代码是在从最一开始最基本的到相对完整的一个过渡,可以理解的看一看,从一开始只是单纯的远程调用 user-service ,到加入eureka,负载均衡(Ribbon),熔断(Hystix),Feign等等,大家可以根据需要去设置超时时长等参数。
在包 consumer 中创建 client 包,然后在 client 包中创建 UserClient 接口和 UserClientImpl 类。
使用 Feign 的时候 需要写一个接口,要想使用 Feign 的负载均衡什么的需要写一个接口的实现类。
在使用 Feign 的时候,Controller 中的方法也要注意变化。而且还要注意在启动类中加入启动注解。
接口代码:
package cn.itcast.consumer.client;
import cn.itcast.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "user-service",fallback = UserClientImpl.class)//开启Feign功能和使用熔断
public interface UserClient {
@GetMapping("user/{id}")
User queryById(@PathVariable("id") Integer id);
}
实现类代码:
package cn.itcast.consumer.client;
import cn.itcast.consumer.pojo.User;
import org.springframework.stereotype.Component;
//Feign里配置熔断
@Component//注入进Spring容器
public class UserClientImpl implements UserClient {
@Override
public User queryById(Integer id) {
User user = new User();
user.setUsername("未查询到");
return user;
}
}
这个配置文件创造和 user-service 相同:
server:
port: 8082
spring:
application:
name: consumer-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
#在Feign中需要配置超时时长,开启hystrix
ribbon:
ConnectionTimeOut: 500
ReadTimeOut: 2000
feign:
hystrix:
enabled: true
这是一个注册中心,Eureka就好比是滴滴,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过“心跳”机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。
创建方法同创建 user-service,在cloud-demo下 New 一个 Module 选择Maven工程,输入名称。
在 eureka-service 的 pom 中引入依赖:
<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>
<artifactId>cloud-demoartifactId>
<groupId>cn.itcast.demogroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>eureka-serviceartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
project>
在 eureka-service => src => main => java 中创建包cn.itcast,并在其中创建EurekaService类
启动类代码:
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer//启动eureka
@SpringBootApplication
public class EurekaService {
public static void main(String[] args) {
SpringApplication.run(EurekaService.class);
}
}
方法同前
server:
port: 10087
#需要给服务起一个名字
spring:
application:
name: eurrka-server
#MAP集合的配置需要在下面配置,前面是键后面是值,这里是另外一个eureka的地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。
方法同上。
在pom中导入:
<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>
<artifactId>cloud-demoartifactId>
<groupId>cn.itcast.demogroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>gatewayartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
dependency>
dependencies>
project>
在 gateway => src => main => java 中创建包cn.itcast,并在其中创建GatewayApplication类
GatewayApplication代码:
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}
在包 cn.itcast 中创建 filter 包并在 filter 包中创建 LoginFliter 类
编写代码:
package cn.itcast.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class LoginFilter extends ZuulFilter {
@Override
//类型
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
//顺序
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
//要不要过滤
public boolean shouldFilter() {
return true;
}
@Override
//业务逻辑
public Object run() throws ZuulException {
//获取请求上下文
RequestContext ctx = RequestContext.getCurrentContext();
//获取request
HttpServletRequest request = ctx.getRequest();
//获取请求参数access-token
String token = request.getParameter("access-token");
//判断是否存在
if(StringUtils.isBlank(token)){
//不存在,未登录,则拦截,不管的话默认放行
ctx.setSendZuulResponse(false);
//返回403
ctx.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
}
return null;
}
}
创建方法同上。
server:
port: 10010
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10087/eureka
#路由功能:
zuul:
prefix: /api #添加前缀,访问的时候也要添加前缀,http://localhost:10010/api/user/user/1
routes:
#路由id
user-service: /user/**
#最终简化版,key(路由id)是服务的id,值是服务的映射(/user/**),有默认的 user-service: /user-service/**可以不用写,它自动从eureka上获取
# path: /user/** #访问以user打头的所有路径,用户请求到达,首先匹配路径,在转发到serviceID那个服务,访问的时候是http://localhost:10010/user/user/1,两个user
# url: http://127.0.0.1:8081 #转发到这个地址
#serviceId: user-service
ignored-services:
- consumer-service
#不想被访问到的服务,集合形式配置方式
# - consumer-service ,后面可以这样罗列
spring:
application:
name: gateway
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
ribbon: #这个时长相加*2不要超过hystrix的时长
Connectionyimeout: 500
ReadTimeout: 2000
这是第一次写博客,也是自己第一次进行学习记录,希望大家可以指出一些不足,大家一起进步。文章是个人的学习笔记,记录,不是教程,毕竟我只是一个刚学java的小菜鸟,所以这个文章仅供参考,要是能帮助到别人就更好啦~QWQ