SpringCloud学习-1

发布时间 2023-06-26 22:02:02作者: Meer_zyh

SpringCloud学习第一天

服务间调用

先实现一个小案例:创建两个项目user-service(服务提供方)和consumer(服务消费方),在user-service项目中查询数据库获取user信息,在consumer项目中调用user-service中的服务获取到user信息。将两个项目创建到一个聚合工程下,创建springCloudDemo父工程,pom文件部分代码如下:

<modules>
  <module>user-service</module>
  <module>consumer</module>
</modules>
<packaging>pom</packaging>
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>10.0.2</java.version>
  <spring-cloud.version>Finchley.SR1</spring-cloud.version>
  <mapper.starter.version>2.0.3</mapper.starter.version>
  <mysql.version>5.1.32</mysql.version>
</properties>
<dependencyManagement>
  <!-- 子工程手动继承 -->
  <dependencies>
    <!-- springCloud -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>

    <!-- 通用mapper -->
    <dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper-spring-boot-starter</artifactId>
      <version>${mapper.starter.version}</version>
    </dependency>

    <!-- mysql驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql.version}</version>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <!-- 子工程自动继承 -->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
</dependencies>

在springCloudDemo父工程中新建Module子工程,创建user-service项目,user-service主要实现通过主键id查询数据库获取user信息,部分代码如下:

User

@Table(name= "user")
@Data
public class User {
    @Id // 主键
    @KeySql(useGeneratedKeys = true)
    private Long id;
    // 用户名
    private String username;
    // 密码
    private String password;
    // 姓名
    @Transient
    private String name;
}

UserDao

为了方便这里使用了通用mapper

@Repository
public interface UserDao extends Mapper<User>{
}

UserService

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public User queryById(Long id) {
        User user = userDao.selectByPrimaryKey(id);
        return user;
    }
}

UserController

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        User user = userService.queryById(id);
        return user;
    }
}

启动服务,访问http://localhost:8081/user/1可以获取到用户信息。

创建consumer项目,通过调用user-service中的服务,获取user信息,这里使用的是Spring的RestTemplate来实现,代码如下:

启动类中注册RestTemplate Bean

@SpringBootApplication
public class ConsumerApplication {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();  // restTemplate获取到可以调用其他服务器接口的实例对象
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }
}

ConsumerController

@RestController
@RequestMapping("consumer")
public class ConsumerController {
  @Autowired
  private RestTemplate restTemplate;
  
  @GetMapping("{id}")
  public String queryById(@PathVariable("id") Long id) {
    String url = "http://localhost:8081/user/"+id;
    String user = restTemplate.getForObject(url, String.class);
    
    return user
  }
}  

同时启动两个项目,访问localhost:8082/consumer/1,可以调用user-service项目中的接口,获取到user信息。

上面的小案例实现了服务之间的调用,但是存在很大的问题,调用方写死了服务方的ip地址,难以维护,无法做集群,无法管理服务等问题,因此开始学习SpringCloud注册中心Eureka。

Eureka

Eureka为注册中心,用于注册所有的服务项目,统一管理,并与服务间维持心跳,检测服务是否宕机,也可以实现服务的集群管理,下面优化上面案例的服务调用。

在springCloudDemo父工程中新建一个eureka-server项目,引入依赖

<dependencies>
  <dependency>
    <!-- Eureka 服务端 -->
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  </dependency>
</dependencies>

启动类

@EnableEurekaServer // 标记是eureka注册中心的服务
@SpringBootApplication
public class EurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer.class);
    }
}

application.yml

server:
  port: 10001
spring:
  application:
    name: eureka-server # 服务的名称,不配置eureka服务不显示名称,会出现unknown
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka	# eureka服务注册的地址,向自己注册,eureka本身也是一个服务,也会注册到注册中心

修改之前的user-service和consumer项目

1、引入依赖

<dependencies>
  <!-- Eureka client依赖 -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
</dependencies>

2、yml

# user-service
server:
  port: 8081
spring:
  application:
    name: user-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka
      
# consumer
server:
  port: 8082
spring:
  application:
    name: consumer-client
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka

3、启动类加注解

@EnableDiscoveryClient // 标识为注册服务端的客户端

将以上三个项目启动,访问eureka-server项目localhost:10001可以看到注册服务列表中有三个服务,修改ConsumerController.java,动态获取调用服务的url

ConsumerController

@RestController
@RequestMapping("consumer")
public class ConsumerController {
  @Autowired
  private RestTemplate restTemplate;
  
  @Autowired
  private DiscoveryClient discoveryClient;    // 使用DiscoveryClient获取eureka实例对象
  
  @GetMapping("{id}")
  public String queryById(@PathVariable("id") Long id) {
    // 根据服务id获取实例,服务id:yml中的name
    List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
    // 从实例中取出ip和端口,取第一个
    ServiceInstance instance = instances.get(0); 
    // 拼接url
    String url = "http://"+instance.getHost()+":"+instance.getPort()+"/user/" + id;
    // String url = "http://localhost:8081/user/"+id;
    
    String user = restTemplate.getForObject(url, String.class);
    return user
  }
}  

以上根据服务名称获取服务instances,获取动态服务地址,重新启动consumer服务访问localhost:8082/consumer/1,可以调用到user-service项目中的接口,获取到user信息。

实现eureka集群

修改eureka-server的yml文件

server:
  port: 10002
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka #将10002的eureka注册到10001,将10001的eureka注册到10002

重新开启一个tomcat启动,修改user-service和consumer项目yml,增加一个eureka注册地址http://127.0.0.1:10002/eureka

# user-service
server:
  port: 8081
spring:
  application:
    name: user-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka,http://127.0.0.1:10002/eureka
      
# consumer
server:
  port: 8082
spring:
  application:
    name: consumer-client
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10001/eureka,http://127.0.0.1:10002/eureka

重新启动user-service和consumer项目,此时locahost:10001和localhost:10002都可以访问到服务列表,localhost:8082/consumer/1也可以成功调用接口,此时关闭一台eureka服务,仍然可以访问,实现了eureka集群。