前言
今天想要开发一个springcloud项目,使用idea2018.2版本,和maven3.6.0,和jdk1.8,话不多说,直接开干。
操作
1、首先我们要新建一个maven父工程,这个工程用来包装我们所有的微服务model。
2、完成后项目如下图,但是由于是父工程,建议删除src文件
然后在pom.xml里面添加配置文件,如图所示
配置文件代码为:
<!--基于springboot开发-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>
<!--父工程引入springcloud配置-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3、然后右击项目工程选择new,model添加子工程
eureka-server
4、前几步与创建父工程一样
5、起一个子工程的项目名称,这里我们是要新建一个注册中心eureka
6、在eureka工程里面添加配置
配置文件为:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
7、在eurka中新建java和resource文件夹
8、在resource下新建application.yml,并加入如下内容
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone:
http://${eureka.instance.hostname}:${server.port}/eureka/
9、我们新建启动类,如图
package com.xiaoqi.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String [] args){
SpringApplication.run(EurekaApplication.class, args);
}
}
10、给java文件夹添加属性
然后我们启动就创建完成eureka了
网页访问http://localhost:8761/ 如下图所示证明成功。
eureka-user
1、现在我们来搭建eureka-user服务model,首先还是在父工程下新建一个model
中间步骤跟创建eureka-server相同,我就不再赘述。
文件夹位置要注意在父目录之下。
pom.xml文件添加如下配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-start-eureka</artifactId>
</dependency>
application.yml配置
server:
port: 8000
eureka:
instance:
prefer-ip-address: true
client:
service-rul:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka-user
创建Application类
@EnableEurekaClient
@RestController
public class Application {
@RequestMapping("/hello")
public String home(){
return "hello world!";
}
public static void main(String [] args){
SpringApplication.run(Application.class, args);
}
}
启动Application
访问http://localhost:8761/ 页面显示如下图证明成功
eureka-order
首先在父工程下创建一个model
pom.xml中添加配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
application.yml配置
server:
port: 7900
eureka:
instance:
prefer-ip-address: true
client:
service-rul:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka-order
创建Order类
package com.xiaoqi.springcloud.po;
public class Order {
private String id;
private Double price;
private String receiverName;
private String receiverAddress;
private String receiverPhone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getReceiverName() {
return receiverName;
}
public void setReceiverName(String receiverName) {
this.receiverName = receiverName;
}
public String getReceiverAddress() {
return receiverAddress;
}
public void setReceiverAddress(String receiverAddress) {
this.receiverAddress = receiverAddress;
}
public String getReceiverPhone() {
return receiverPhone;
}
public void setReceiverPhone(String receiverPhone) {
this.receiverPhone = receiverPhone;
}
@Override
public String toString() {
return "Order{" +
"id='" + id + '\'' +
", price=" + price +
", receiverName='" + receiverName + '\'' +
", receiverAddress='" + receiverAddress + '\'' +
", receiverPhone='" + receiverPhone + '\'' +
'}';
}
}
创建Controller
package com.xiaoqi.springcloud.controller;
import com.xiaoqi.springcloud.po.Order;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
/*
* 通过id查询订单
* */
@GetMapping("/order/{id}")
public String findOrderById(@PathVariable String id){
Order order = new Order();
order.setId("123");
order.setPrice(23.5);
order.setReceiverAddress("beijing");
order.setReceiverName("xiaoqi");
order.setReceiverPhone("15800000000");
return order.toString();
}
}
在eureka-user启动类中加入如下代码,这是RestTemplate的Spring实例,RestTemplate是Spring提供的用于访问Rest服务的客户端实例,它提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
在eureka-user中编写UserController用户控制器类
由于现在还没有创建数据库,所以不能够成功查询,现在我们创建数据库
数据库名称为microservice
添加两条数据
在eureka-order 的pom.xml中添加如下
<!--MyBatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!--MySql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
在eureka-order中新建UserMapper
@Mapper
public interface UserMapper {
//查询所有用户
@Select("select * from tb_user")
List<User> getAllUsers();
//删除用户
@Delete("delete from tb_user where id=#{id}")
void delete(Integer id);
}
建立User类
public class User {
private Integer id;
private String username;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
UserServiceImpl类
@Service
@Transactional
public class UserServiceImpl implements UserService {
//注入用户Mapper
@Autowired
private UserMapper userMapper;
//查询所有用户
public List<User> getAllUsers() {
return this.userMapper.getAllUsers();
}
//删除用户
public void deleteUser(Integer id) {
System.out.println("删除了id为"+id+"的用户");
this.userMapper.delete(id);
}
UserService接口
public interface UserService {
//查询所有
List<User> getAllUsers();
//删除数据
void deleteUser(Integer id);
}
UserController类
@RestController
@RequestMapping("/user")
public class UserController {
//注入用户Service
@Autowired
private UserService userService;
//查询所有用户
@RequestMapping("/userList")
public List<User> getAllUsers(){
List<User> list = this.userService.getAllUsers();
return list;
}
//删除用户
@RequestMapping("/delete/{id}")
public void delete(@PathVariable Integer id){
this.userService.deleteUser(id);
}
然后检查eureka-user的Controller
然后按顺序分别启动eureka-server、eureka-order、eureka-user
然后访问
http://localhost:8000/findOrdersByUser/1
如图
这样就证明访问成功了
Ribbon
Ribbon是用来实现负载均衡的
首先我们在eureka-user中Application的@Bean下加注解@LoadBalanced
,加了这个注解后RestTemplate就具有了负载均衡能力。
然后将eureka-user中的UserController进行如下修改
我们将之前的“主机地址+端口号”变成了实例名称
在order中写一个工具类
@Configuration
public class ServiceInfoUtil implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
/**
* 声明event对象,该对象用于获取运行服务器的本地端口
*/
private static EmbeddedServletContainerInitializedEvent event;
public void onApplicationEvent(
EmbeddedServletContainerInitializedEvent event){
ServiceInfoUtil.event = event;
}
/**
* 获取端口号
*/
public static int getPort(){
int port = event.getEmbeddedServletContainer().getPort();
return port;
}
然后在userList接口中写一个输出,这是用来输出端口号
然后将eureka-order先启动一次,再把端口号该为7901再启动一次
可以看到启动了两个order服务
然后我们访问http://localhost:8000/findOrdersByUser/1
我们多访问几次,然后看输出
我们可以看到,这两个不同端口的order都访问到了,证明Ribbon实现了负载均衡机制。
eureka-user-hystrix
接下来我们写hystrix模块,简单了来说就是熔断器模块,因为在系统中例如c服务调用b服务,然后b服务调用a服务,假如a服务出现问题,那么会导致b服务出现问题,然后再导致c服务出现问题,最终整个系统全部瘫痪,为了解决这个问题就出现了熔断器。
1、新建eureka-user-hystrix模块,步骤和上面的其他模块一样,pom.xml中添加如下配置。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
yml文件如下
server:
port: 8030
eureka:
instance:
prefer-ip-address: true
client:
service-rul:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka-user-hystrix
新建启动类
@SpringBootApplication
@EnableCircuitBreaker
@EnableEurekaClient
public class Application {
public static void main(String [] args){
SpringApplication.run(Application.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
新建UserController,代码中的fallbackInfo方法就是在指定的服务出现问题不能访问的时候就会走这个方法,当指定的服务问题解决以后又会自动再访问指定的访问,这里是自动熔断与连接的。
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
/**
* 查找与用户相关的订单
*/
@GetMapping("/findOrdersByUser/{id}")
@HystrixCommand(fallbackMethod = "fallbackInfo")
public String findOrdersByUser(@PathVariable String id){
return this.restTemplate.getForObject("http://eureka-order/user/userList", String.class);
}
/**
* 返回信息方法
*/
public String fallbackInfo(@PathVariable String id){
return "服务不可用,请稍后再试!";
}
}
现在我们来依次启动项目,order启动两个,分别为7900和7901
启动后访问http://localhost:8761/ 如下图证明启动成功
然后访问http://localhost:8030/findOrdersByUser/1 如下图
然后我们就多访问几次,发现访问正常,而且负载也正常
这个时候我们停掉7901的服务
然后我们再次刷新之前的路径,当负载到7901的接口的时候出现下图证明成功
然后我们再启动7901服务后,再次访问就不会出现上图情况,证明我们熔断器配置成功。
gateway-zuul
接下来我们创建zuul(网关)模块,网关可以用来执行认证、动态路由、安全和动态响应等功能,这里主要讲一下动态路由。
新建gateway-zuul,pom.xml配置如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
yml配置如图
新建启动类
@EnableZuulProxy
@SpringBootApplication
@EnableEurekaClient
public class Application {
public static void main(String [] args){
SpringApplication.run(Application.class, args);
}
}
然后我们依次启动注册中心(eureka-server)、服务提供者(eureka-order)、网关服务(gateway-zuul)
然后我们访问 http://localhost:7900/order/1
出现下图证明成功
config-server
接下来我们创建配置模块,因为我们以后可能随着业务越来越大,我们会从单体系统升级为分布式系统,但是我们每一个模块都有一个配置文件,这样我们要修改一个模块的配置文件,就需要找到该模块的所有文件,一个一个修改。