PinkGuy / SpringMVC学习
Created 0001-01-01 Modifyd 0001-01-01

2191 Words

[TOC]

单体应用存在的问题(为什么要用SpringCloud)

  • 随着业务的发展,开发变得越来越复杂。
  • 修改,新增某个功能,需要对整个系统进行测试,部署。
  • 一个模块出现问题,很可能导致整个系统的崩溃。
  • 开发团队同时对数据进行管理,容易产生安全漏洞。
  • 各个模块使用同一种技术进行开发,各个模块很难根据实际的情况选择更适合的技术框架,局限性很大/
  • 模块内容过于复杂,如果员工离职,交接难度,所需时间提升很大。

分布式,集群

集群:一台服务器无法承受高负荷并发的数据访问量,那就开十台服务器,十台不够就开一百台(物理层面)。很多人干同一件事情,来分担压力。

分布式:将一个复杂的问题差分成若干个小问题,将一个大型的项目拆分成若干个微服务来协同完成(软件设计层面)。将一个庞大的工作拆分成若干个小步骤,交给不同的人员来做,最后将所有结果整合实现大的需求。

服务治理的核型分为三部分:*注册中心*,*服务提供者*,*服务消费者*。

再分布式系统中,每个微服务启动时,将自己的信息储存到注册中心,这叫服务注册。

服务消费者通过注册中心获取到服务提供者的网络信息,通过该信息调用服务,这叫服务发现。

Spring Cloud Eureka

  • Eureka Server, 注册中心;

  • Eureka Client,所有需要进行注册的微服务通过 Eureka Client来连接到Eureka Server进行注册;

Eureka Server(注册中心)代码实现

  • 创建一个父工程,pom.xml如下:

    <?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>
    <packaging>pom</packaging>
    <modules>
        <module>eurekaaservice</module>
        <module>eurekaclicent</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xxh</groupId>
    <artifactId>aispringcloud3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aispringcloud3</name>
    <description>Demo project for Spring Boot</description>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    </repositories>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </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>
    </dependencies>
    
    
    <!--    spring cloud依赖 注意版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.BUILD-SNAPSHOT</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>
    
  • 在父工程下创建Module(eurekaserver),pom.xml

    <dependencies>
    <dependency> 
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
    </dependencies>
    
  • 创建application.yml添加相应配置

    server:
    port: 8761
    eureka:
    client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/
    

属性说明

server.port:当前Eureka Service服务的端口;

eureka.client.register-with-eureka:是否对当前 Eureka Service 服务当成客户端进行注册。

eureka.client.fetch-registry:是否获取其他 Eureka Service 服务的数据;

eureka.client.service-url.defaultZone:注册中心的访问地址。

  • 创建启动类(EurekaServerApplication)

    package com.xxh;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
    }
    

注解说明

@SpringBootApplication:声明当前类是一个spring boot 入口

@EnableEurekaServer:声明当前类是一个 Eureka Service 微服务,提供注册和服务发现。就是注册中心;

![]()

Eureka Client (服务提供者)代码实现

  • 创建Client ,pmx.xml 代码

    <dependencies>
    	<!--        服务提供者依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
    
        <dependency><!--        启动不起来,再加入-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
  • 添加application.yml; 配置

    server:
    port: 8010
    spring:
    application:
    name: provider
    eureka:
    client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    instance:
    prefer-ip-address: true
    

属性说明

spring.application.name:注册到服务中心的名称

eureka.client.service-url.defaultZone:注册中心的访问地址

eureka.instance.prefer-ip-address:是否将当前服务的 IP 注册到 Eureka Service。

  • 启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.http.EurekaApplications;
    
    @SpringBootApplication
    public class ProviderApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
    }
    
  • 将Client注册到Eureka,先启动Eureka再Client后进入到http://localhost:8761/

#### Eureka Client URUD操作

  • 创建entity层 添加 JavaBean-Student; ()

    public class Student {
    
    private long id;
    private String name;
    private int age;
    }
    
  • 创建dao接口

    package com.clicent.dao;
    
    
    import com.clicent.entity.Student;
    
    import java.awt.*;
    import java.util.Collection;
    
    public interface UserDao {
    
    Collection<Student> loadAll();
    
    Student getById(Long id);
    
    void seveOrUpdate(Student stu);
    
    void dalete(long id);
    
    }
    
  • 创建dao实现类

    package com.clicent.dao.impl;
    
    import com.clicent.dao.UserDao;
    import com.clicent.entity.Student;
    import org.springframework.stereotype.Repository;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    
    @Repository
    public class UserDaoImpl implements UserDao{
    
    private static Map<Long,Student> studentMap;
    
    static {
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"刘波",15));
        studentMap.put(2L,new Student(2L,"洲书院",1475));
        studentMap.put(3L,new Student(3L,"上级领导",15));
    
    }
    
    @Override
    public Collection<Student> loadAll() {
    
        return studentMap.values();
    }
    
    @Override
    public Student getById(Long id) {
        return studentMap.get(id);
    }
    
    @Override
    public void seveOrUpdate(Student stu) {
        studentMap.put(stu.getId(),stu);
    }
    
    @Override
    public void dalete(long id) {
        studentMap.remove(id);
    }
    }
    
  • 创建Controller调用

    package com.clicent.controller;
    
    import com.clicent.dao.impl.UserDaoImpl;
    import com.clicent.entity.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.Collection;
    
    @RestController //传入为json格式
    public class UserController {
    
    
    @Autowired
    private UserDaoImpl udi;
    
    @GetMapping("/loadAll")
    public Collection<Student> load(){
      return  udi.loadAll();
    }
    
    
    @GetMapping("/get/{id}")
    private Student get(@PathVariable("id") long id){
        return  udi.getById(id);
    }
    
    
    @PostMapping("/update")
    private void seveOrUpdate(@RequestBody Student stu){
        udi.seveOrUpdate(stu);
    }
    
    @DeleteMapping("/delete/{id}")
    private void delete(@PathVariable("id") long id){
        udi.dalete(id);
    }
    
    }
    

RestTemplate 的使用

  • 什么是ResTemplate?

RestTemplate 是 Spring 框架提供的基于 REST 的服务组织,底层对HTTP进行请求及响应进行封装,提供了很多REST服务的方法,可以简化代码开发。

  • 使用RestTemplate;

1,创建工程,pom.xml(可能需要添加)

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.0.RELEASE</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2,创建实体类(与需要调用的实体类一致)

public class Student {

    private long id;
    private String name;
    private int age;
}

3,编写Controller

package com.rest.controller;

import com.rest.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;
import java.util.List;

@RestController
@RequestMapping("/rest")
public class RestTemController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/loadAll")
    public Collection<Student> load(){
       return restTemplate.getForEntity("http://localhost:8010/loadAll", Collection.class).getBody();
    }


    @GetMapping("/get/{id}")
    private Student get(@PathVariable("id") long id){
        return  restTemplate.getForEntity("http://localhost:8010/get/{id}",Student.class,id).getBody();
    }


    @PostMapping("/update")
    private void seveOrUpdate(@RequestBody Student stu){
       restTemplate.postForEntity("http://localhost:8010/update",stu,null).getBody();
    }


    @DeleteMapping("/delete/{id}")
    private void delete(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/delete",id);
    }

}

4,编写启动类

package com.rest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class RestTemperatureApplication {

    public static void main(String[] args) {

        SpringApplication.run(RestTemperatureApplication.class,args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}


服务消费者 consumer

  • 创建 Maven 工程,pom.xml;

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
    </dependencies>
    
  • 添加application.yml

    server:
    port: 8020
    eureka:
    client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    instance:
    prefer-ip-address: true
    spring:
    application:
    name: consumer
    
  • 创建启动类

    package com.cn;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    public class ConsumerApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    
    }
    
    
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    }
    
    
  • controller层

    package com.cn.controller;
    
    import com.cn.entity.Student;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Collection;
    
    @RestController
    @RequestMapping("/controller")
    public class ConsumerController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/loadAll")
    public Collection<Student> load(){
       return restTemplate.getForEntity("http://localhost:8010/loadAll", Collection.class).getBody();
    }
    
    
    @GetMapping("/get/{id}")
    private Student get(@PathVariable("id") long id){
        return  restTemplate.getForEntity("http://localhost:8010/get/{id}",Student.class,id).getBody();
    }
    
    
    @PostMapping("/update")
    private void seveOrUpdate(@RequestBody Student stu){
       restTemplate.postForEntity("http://localhost:8010/update",stu,null).getBody();
    }
    
    
    @DeleteMapping("/delete/{id}")
    private void delete(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/delete",id);
    }
    
    }
    
    
  • 最后 http://localhost:8020/controller/ 调用即可