SpringCloud study Notes

The study notes are compiled according to the SpringCloud tutorial of qianfeng education.

As shown in the video tutorial: www.bilibili.com/video/BV18Z…

I. Introduction to SpringCloud

1.1 Microservices Architecture

Microservices framework author: Martin Fowler

Martinfowler.com/articles/mi…

In short, the microservice architecture style is a way of developing a single application as a set of small services, each running in its own process and communicating with a lightweight mechanism (usually HTTP resource apis). These services are built around business functions and can be deployed independently by a fully automated deployment mechanism. There is little centralized management of these services, which can be written in different programming languages and use different data storage technologies.

  1. Microservices architecture is just a style, a style
  2. A complete project, split multiple modules to develop separately
  3. Each module runs separately in its own container
  4. Each module needs to communicate with each other. Http, RPC, MQ
  5. Each module has no dependencies and is deployed separately
  6. Multiple languages can be used to develop different modules
  7. Use MySQL data, Redis, ES to store data, or use multiple MySQL databases

Summary: Divide complex and bloated single applications into fine-grained services, and package and deploy each service separately.

1.2 introduce SpringCloud

SpringCloud is a set of technology stacks that land the microservices architecture.

Most of the technologies in the SpringCloud stack are secondary development based on Technologies from Netflix

1. SpringCloud Chinese website: www.springcloud.cc/

Eight technical points:

  1. Eureka – Registration and discovery of services
  2. Robbin – Load balancing between services
  3. Feign – Communication between services
  4. Hystrix – Thread isolation for services as well as circuit breakers
  5. Zuul – Service Gateway
  6. Stream – Enables the use of MQ
  7. Config – Dynamic configuration
  8. Sleuth – Service tracking

Registration and discovery of services -Eureka

2.1 the introduction

Eureka helps us maintain all the service information so that services can call each other.

She solved two problems:

  1. If the caller, IP, or port number changes, the caller needs to be maintained
  2. If the called builds a cluster, maintain all the callers

2.2 Eureka quick Start

2.2.1 create EurekaServer

1. Create a parent project, specify the version of SpringCloud in the parent project, and change packing to POM

<packaging>pom</packaging>

<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>
Copy the code

2, create Eureka server: create SpringBoot project, and import dependencies, add annotations in the boot class, write YML file

2.1. Import dependencies

 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

2.2. Add annotations to start classes

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); }}Copy the code

2.3. Write yML configuration files

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://root:root@${eureka.instance.hostname}:${server.port}/eureka/
spring:
  security:
    user:
      name: root
      password: root
  application:
    name: EUREKA
Copy the code

2.2.2 create EurekaClient

1. Create a Maven project and change it to SpringBoot

<parent>
<artifactId>springcloudstudy</artifactId>
<groupId>com.chtgeo</groupId>
<version>0.0.1 - the SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>02-customer</artifactId>

Copy the code

2. Import dependencies

<dependencies>
	<dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
Copy the code

3. Add annotations to the startup class

@SpringBootApplication
@EnableEurekaClient
public class CustomerApplication {
    public static void main(String[] args) { SpringApplication.run(CustomerApplication.class, args); }}Copy the code

4. Write a configuration file

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

spring:
  application:
    name: CUSTOMER
Copy the code

2.2.3 test had been

1. Create a Search module and register with Eureka

2. Use EurekaClient object to obtain service information

@Autowired
private EurekaClient eurekaClient;
Copy the code

3. Call the normal RestTemplate

@GetMapping("/customer")
public String customer(a) {

    // 1. Use eurakaClient to obtain information about the SEARCH service
    InstanceInfo search = eurekaClient.getNextServerFromEureka("SEARCH".false);
    2. Obtain the access address
    String homePageUrl = search.getHomePageUrl();

    // 3. Access the vm using restTemplate
    String result = restTemplate.getForObject(homePageUrl + "/search", String.class);

    4 / / return
    return result;

}
Copy the code

2.3 Safety of Eureka

Implement Eureka authentication

1. Import dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
Copy the code

2. Write configuration classes

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http); }}Copy the code

3. Write a configuration file

User name and password
spring:
  security:
    user:
      name: root
      password: root
Copy the code

4. Other services need to add user names and passwords when registering with Eureka

eureka:
  client:
    serviceUrl:
      defaultZone: http://user name: password @localhost:8761/eureka/
Copy the code

2.4 High availability of Eureka

If the program works, suddenly Eureka goes down.

1. If the caller has visited the called party once, Eureka downtime will not affect the calling function.

2. If the caller has not accessed the called, the Eureka outage will cause the current function to be unavailable.

Build Eureka high availability

1. Prepare multiple Eurekas

The imL and target files are copied, and the project name in pom.xml is modified to add a module to the parent project.Copy the code

2. Register the service with multiple EureKas

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
Copy the code

3. Multiple EureKas communicate with each other

eureka:
  client:
    registerWithEureka: true # Sign up for Eureka
    fetchRegistry: true # Pull information from Eureka
    serviceUrl:
      defaultZone: http://root:root@localhost:8762/eureka/
Copy the code

2.5 Details of Eureka

1. When EurekaClient is started, register your registration information with EurekaServer, which will store the registration information of EurekaClient.

2. When EurekaClient invokes the service, if there is no local cache of registration information, go to EurekaServer to obtain registration information.

3. EurekaClient will connect to EurekaServer through heartbeat. (By default, EurekaClient will send a heartbeat request every 30 seconds. If you do not send a heartbeat message after 90 seconds, EurekaServer will consider you down and remove the current EurekaClient from the registry.)

eureka:
  instance:
    lease-renewal-interval-in-seconds: 30 # Heartbeat interval
    lease-expiration-duration-in-seconds: 90 # How long have you not sent it
Copy the code

4. EurekaClient updates the local registry in EurekaServer every 30 seconds

eureka:
  client:
    registry-fetch-interval-seconds: 30 How often do you update the local registry cache information
Copy the code

5. Eureka’s self-protection mechanism. If the heartbeat sending rate of a service is lower than 85% within 15 minutes, EurekaServer will enable the self-protection mechanism.

  1. – EurekaServer will not remove services that have not received heartbeats for a long time
  2. EurekaServer is still available
  3. When the network is stable, EurekaServer starts to synchronize its information with other nodes
eureka:
  server:
    enable-self-preservation: true # Turn on the self-protection mechanism
Copy the code

6, CAP theorem: C- Consistency, A- Availability, P-partition tolerance. In distributed environment, only two of these three features can be satisfied, and fault tolerance of partition must be satisfied in distributed environment, and can only be balanced between AC.

CP: The consistency is guaranteed, but your system may be unavailable for a certain period of time. If you synchronize data for a long time, the loss will be great.

AP: Ensure availability, Eureka is an AP effect, highly available cluster, Eureka cluster is centrless, even if the Eureka down several will not affect the use of the system, do not need to re-elect a master, will also lead to a certain period of data inconsistency.

3. Load balancing of services -Robbin

3.1 the introduction

Robbin helps us to implement service and service load balancing. Robbin belongs to client load balancing

Client load balancing: customer customer module, pulls all information of the two Search modules to the local cache, makes a load balancing policy in Customer, and selects a certain service.

Server load balancing: in the registry, select a specified service information based on the load balancing policy you specify and return it.

3.2 Quick start of Robbin

1. Start two Search modules

2. Import two Robbin modules in Customer

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Copy the code

3. Integrate RestTemplate and Robbin

@Bean
@LoadBalanced
public RestTemplate restTemplate(a) {
    return new RestTemplate();
}
Copy the code

4. Access search from Customer

@GetMapping("/customer")
public String customer(a) {
	String result = restTemplate.getForObject("http://SEARCH:8082/search", String.class);
    4 / / return
    return result;
}
Copy the code

3.3 Robbin Configuring load balancing policies

1. Load balancing policy

  1. RandomRule: a RandomRule strategy
  2. RoundRobbinRule: indicates a polling policy
  3. WeightedResponseTimeRule: The default is polling and you are automatically assigned weights based on how long the service takes
  4. BestAvailableRule: Allocation is based on the smallest number of concurrent requests from the called party

2. Take the form of notes

@Bean
public IRule ribbon(a) {
	return new BestAvailableRule();
}
Copy the code

3. Configure file to specify load balancing policy (recommended)

SEARCH: # service name
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # Specify the class used by the load balancing policy
Copy the code

4. Calls between services -Feign

4.1 the introduction

Feign can help us with interface oriented programming, which is to call other services directly and simplify development.

4.2 Quick start of Feign

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Copy the code

2. Add annotations

@EnableFeignClients
Copy the code

Create an interface and map it to the Search module

@FeignClient(value = "SEARCH") // Specify the service name
public interface SearchClient {

    // value: indicates the request path of the target server. Method: indicates the mapping method
    @RequestMapping(value = "/search", method = RequestMethod.GET)
    String search(a);
}
Copy the code

4. Test use

@Autowired
private SearchClient searchClient;

@GetMapping("/customer")
public String customer(a) {
    String result = searchClient.search();
    return result;
}
Copy the code

4.3 Transmission of Feign parameters

1. Precautions

  1. If the parameters to be passed are complex, POST is used by default.
  2. When passing a single parameter, it is recommended to use @pathVariable. If many parameters are passed, you can use @requestParam instead of leaving out the value attribute.
  3. When passing object information, use JSON and add @RequstBody
  4. The Client interface must use @RequestMapping

2. Prepare three interfaces under the Search module

@GetMapping("/search/{id}")
public Customer findById(@PathVariable Integer id) {
	return new Customer(1."Zhang".23);
}

@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id, @RequestParam String name) {
	return new Customer(id, name, 23);
}

@PostMapping("/save")
	public Customer save(@RequestBody Customer customer) {
	return customer;
}
Copy the code

3. Encapsulate the Controller under the Customer module

@GetMapping("/customer/{id}")
public Customer findById(@PathVariable Integer id) throws InterruptedException {
    return customerService.findById(id);
}

@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id, @RequestParam String name) {
    return searchClient.getCustomer(id, name);
}

@GetMapping("/save") // Automatically converts to POST request 405
public Customer save(Customer customer) {
    return searchClient.save(customer);
}
Copy the code

4. Encapsulate the Client interface

@RequestMapping(value = "/search/{id}", method = RequestMethod.GET)
Customer findById(@PathVariable(value = "id") Integer id);

@RequestMapping(value = "/getCustomer", method = RequestMethod.GET)
Customer getCustomer(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name);

@RequestMapping(value = "/save", method = RequestMethod.POST)
Customer save(@RequestBody Customer customer);
Copy the code

5, test,

4.4 Feign的Fallback

Fallback can help us use Feign to call another service, if there is a problem, the service degradation, return an error data, avoid the function of a service failure, all failure.

1. Create a POJO class to implement the Client interface.

@Component
public class SearchClientFallBack implements SearchClient {
    @Override
    public String search(a) {
        return "Something's wrong!!";
    }

    @Override
    public Customer findById(Integer id) {
        return null;
    }

    @Override
    public Customer getCustomer(Integer id, String name) {
        return null;
    }

    @Override
    public Customer save(Customer customer) {
        return null; }}Copy the code

2, modify the Client interface annotation, add a property.

@FeignClient(value = "SEARCH",fallback = SearchClientFallBack.class)
Copy the code

3. Add a configuration file.

feign:
  hystrix:
    enabled: true
Copy the code

The caller has no way of knowing what the error message is

1. FallBackFactory is based on Fallback

Create a POJO class to implement FallBackFactory

@Component
public class SearchClientFallBackFactory implements FallbackFactory<SearchClient> {

    @Autowired
    private SearchClientFallBack searchClientFallBack;

    @Override
    public SearchClient create(Throwable throwable) {
        throwable.printStackTrace();
        returnsearchClientFallBack; }}Copy the code

3. Modify the properties of the Client interface

@FeignClient(value = "SEARCH",fallbackFactory = SearchClientFallBackFactory.class)
Copy the code

5. Service isolation and circuit breaker -Hystrix

5.1 the introduction

5.2 Implementation of downgrade mechanism

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Copy the code

2. Add a note

@EnableCircuitBreaker
Copy the code

3. Write its degradation methods for an interface

@GetMapping("/customer/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack")
public Customer findById(@PathVariable Integer id) throws InterruptedException {
        int i = 1 / 0;
        return searchClient.findById(id);
}

// findById degradation method, method description is consistent with the interface
public Customer findByIdFallBack(@PathVariable Integer id) {
    return new Customer(-1."".0);
}
Copy the code

4. Add annotations to the interface

@HystrixCommand(fallbackMethod = "findByIdFallBack")
Copy the code

5. Test it out

5.3 Thread Isolation

If the Tomcat thread pool is used to receive user requests and the current thread is used to perform functions of other services, if a service fails, tomcat threads will accumulate in a large area and Tomcat cannot process other service functions.

1. Hystix thread pool (default) : The thread pool of Tomcat is used when receiving user requests, executing business code, and invoking other services.

Semaphores, again using Tomcat’s thread pool, help us manage Tomcat’s thread pool.

1. Hystix thread pool configuration (see the HystrixCommandProperties class to configure the name property)

  1. Thread isolation policy: name =execution.isolation.strategy, value = THREAD| SEMAPHORE
  2. Timeout period: name=circuitBreaker.enabled,value = true|false

5.4 the breaker

5.4.1 Circuit breakers

When invoking a specified service, if the service failure rate reaches one of the thresholds you entered, change the circuit breaker from close to Open. If the specified service is accessed, use the fallback method. Within a certain period of time, the open state will again change to half open. Allow a request to be sent to my specified service and, if successful, turn to CLOSE. If it fails, the service will turn to open again and loop to half open again until the breaker returns to a close state.

5.4.2 Configuring the Monitoring interface for circuit breakers

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
Copy the code

2. Add annotations to the startup class

@EnableHystrixDashboard
Copy the code

3. Configure a servlet

@WebServlet("/hystrix.stream")
	public class HystrixServlet extends HystrixMetricsStreamServlet {}// Add the scan servlet annotation to the startup class
@ServletComponentScan({"com.chtgeo.servlet"})
Copy the code

4, test,

Direct access: http://host:port/hystrix

Enter the mapped servlet path at the current location

5.4.3 Configuring Circuit breaker attributes

Properties of circuit breakers

To find related properties address: github.com/Netflix/Hys…

  1. Switch of the circuit breaker: name =hystrix.command.default.circuitBreaker.enabled, value = true
  2. Total number of requests for the failure threshold: name=hystrix.command.default.circuitBreaker.requestVolumeThreshold,value=20
  3. Total request failure rate reaches % when: name=hystrix.command.default.circuitBreaker.errorThresholdPercentage,value=50
  4. Force the service to reject the request: name=hystrix.command.default.circuitBreaker.forceOpen,value=false
  5. Force the service to accept the request: name=hystrix.command.default.circuitBreaker.forceClosed,value=false

Specific Configuration modes

@GetMapping("/customer/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack", commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "70"), @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"), })
Copy the code

5.5 Request Caching

5.5.1 Introduction to Request Caching

1. The declaration cycle of the request cache is one request

The request cache is a method that caches the current thread, taking the method parameter as the key and the method return as the value

3. In a request, the target method is called once, and will always be cached.

5.5.2 Implementation of request caching

Create a Service and call the Search Service.

@Service
public class CustomerService {

    @Autowired
    SearchClient searchClient;

    @CacheResult
    @HystrixCommand(commandKey = "findById")
    public Customer findById(Integer id) {
        return searchClient.findById(id);
    }

    @CacheRemove(commandKey = "findById")
    @HystrixCommand
    public void clearFindById(@CacheKey Integer id) {
        System.out.println("FindById cleared..."); }}Copy the code

2. Use request caching annotations

@cacheresult: helps us cache the result of the current method (must be used with @hystrixCommand) @Cacheremove: helps us to clear a cache information (based on commandKey) @cacheKey: specifies which method parameter to use as the cache identifierCopy the code

3. Write the Search module to return the result

return new Customer(1."Zhang", (int) (Math.random()*10000));
Copy the code

4, write Filter to build HystixRequestContext

@WebFilter("/*")
public class HystrixRequestContextInitFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HystrixRequestContext.initializeContext(); filterChain.doFilter(servletRequest, servletResponse); }}Copy the code

5. Modify Controller

public Customer findById(@PathVariable Integer id) throws InterruptedException {
    System.out.println(customerService.findById(id).getAge());
    System.out.println(customerService.findById(id).getAge());
    System.out.println(customerService.findById(id));
    System.out.println(customerService.findById(id));
    customerService.clearFindById(id);
    System.out.println(customerService.findById(id));
    System.out.println(customerService.findById(id));
    System.out.println(customerService.findById(id).getAge());
    System.out.println(customerService.findById(id).getAge());
    return customerService.findById(id);
}
Copy the code

6, test,

Vi. Service gateway -Zuul

6.1 the introduction

Problems solved:

1. The client maintains a large number of IP and port information and directly accesses specified services

2. Authentication and authorization operations need to be added to each module

3. In the iteration of the project, the services need to be split and merged, requiring a lot of changes on the client side

4. Uniformly put the safety check in ZUUL

6.2 Zuul’s Quick Start

1. Create Maven project and change it to SpringBoot project

2. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

3. Add annotations

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

spring:
  application:
    name: ZUUL
server:
  port: 80
Copy the code

4, test,

6.3 Zuul Common Configuration Information

6.3.1 Zuul Monitoring page

1. Import dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code

2. Write a configuration file

# Check the monitoring page of Zuul (use during development, do not configure when online)
management:
  endpoints:
    web:
      exposure:
        include: "*"
Copy the code

3. Direct access

6.3.2 Ignoring Service Configuration

# zuul configuration
zuul:
  * all paths configured by default will be ignored.
  ignored-services: eureka
  The monitoring interface is already viewable, when accessing the service, 404
  ignored-patterns: /**/search/**
Copy the code

6.3.3 Customizing Service Configurations

# zuul configuration
zuul:
  Key (service name: value (path))
# routes:
# search: /ss/**
# customer: /cc/**
  # Specify a custom service (mode 2)
  routes:
    kehu:   # custom name
      path: /ccc/**   # mapping path
      serviceId: customer # service name
Copy the code

6.3.4 Grayscale Publishing

1. Add a configuration class

@Bean
public PatternServiceRouteMapper serviceRouteMapper(a) {
    return new PatternServiceRouteMapper(
        "(? 
      
       ^.+)-(? 
       
        v.+$)"
       
      ."${version}/${name}");
}
Copy the code

2. Prepare a service with two versions

version: v1
spring:
  application:
    name: CUSTOMER-${version}
Copy the code

3. Modify Zuul configuration

zuul:
  [root@localhost] [root@localhost] [root@localhost]
# ignored-services: "*"
Copy the code

4, test,

6.4 Zuul’s filter execution process

When a client sends a request to the Zuul service, it first passes through the PreFilter chain, forwards the request to a RoutingFilter, forwards the request to a specified service, and after the specified service responds to a result, passes through the PostFilter filter chain again, and finally passes the response to the client

6.5 Zuul filter introduction

Create a POJO class that inherits the ZuulFilter abstract class

@Component
public class TestZuulFilter extends ZuulFilter{}
Copy the code

2. Specify the current filter type

@Override
public String filterType(a) {
	return FilterConstants.PRE_TYPE;
}
Copy the code

3. Specify the order in which filters are executed

@Override
public int filterOrder(a) {
    return FilterConstants.PRE_DECORATION_FILTER_ORDER-1;
}
Copy the code

4. Configure whether to enable the function

@Override
public boolean shouldFilter(a) {
    // Enable the current filter
    return true;
}
Copy the code

5, test,

6.6 PreFilter Implements token Verification

1. Prepare access path and request parameters to pass token

http://localhost/v2/customer/version?token=123
Copy the code

2. Create AuthenticationFilter

@Component
public class AuthenticationFilter extends ZuulFilter {
    @Override
    public String filterType(a) {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder(a) {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 2;
    }

    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    @Override
    public Object run(a) throws ZuulException {
        // 1. Obtain the Request object
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        2. Obtain the token parameter
        String token = request.getParameter("token");
        // 3. Compare tokens
        if (token == null || !"123".equals(token)) {
            // 4. The token fails to verify and responds to the data directly
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
        }
        return null; }}Copy the code

3. Write concrete logic code in Run

@Override
public Object run(a) throws ZuulException {
    // 1. Obtain the Request object
    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();
    2. Obtain the token parameter
    String token = request.getParameter("token");
    // 3. Compare tokens
    if (token == null || !"123".equals(token)) {
        // 4. The token fails to verify and responds to the data directly
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
    }
    return null;
}
Copy the code

4, test,

6.7 Zuul service has been downgraded

1. Create POJO class to implement FallbackProvider

@Component
public class ZuulFallBack implements FallbackProvider {}
Copy the code

2. Override both methods

@Override
public String getRoute(a) {
    return "*"; // indicates that all problematic services go through this degradation method
}

@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    // Logs can be processed here
    System.out.println("Degraded service:" + route);
    cause.printStackTrace();
    return new ClientHttpResponse() {
        @Override
        public HttpStatus getStatusCode(a) throws IOException {
            // Specify a specific HttpStatus
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }

        @Override
        public int getRawStatusCode(a) throws IOException {
            // Return the status code
            return HttpStatus.INTERNAL_SERVER_ERROR.value();
        }

        @Override
        public String getStatusText(a) throws IOException {
            // Specify an error message
            return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
        }

        @Override
        public void close(a) {}@Override
        public InputStream getBody(a) throws IOException {
            String msg = Current Services: + route + "There is a problem!!";
            return new ByteArrayInputStream(msg.getBytes());
        }

        @Override
        public HttpHeaders getHeaders(a) {
            // Specify the response header information
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            returnheaders; }}; }Copy the code

3, test,

6.8 Zuul Dynamic Routing

1. Create a filter

@Component
public class DynamicRoutingFilter extends ZuulFilter {
    @Override
    public String filterType(a) {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder(a) {
        // The order of execution is best placed at the end of the Pre filter
        return FilterConstants.PRE_DECORATION_FILTER_ORDER + 2;
    }

    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    @Override
    public Object run(a) throws ZuulException {
        // 1. Obtain Request
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        // 2. Obtain the parameter redisKey
        String redisKey = request.getParameter("redisKey");

        // 3
        if(redisKey ! =null && redisKey.equalsIgnoreCase("customer")) {// http://localhost:8080/customer/1
            context.put(FilterConstants.SERVICE_ID_KEY, "customer-v1");
            context.put(FilterConstants.REQUEST_URI_KEY, "/customer/1");

        }else if(redisKey ! =null && redisKey.equalsIgnoreCase("search")) {// http://localhost:8081/search/2
            context.put(FilterConstants.SERVICE_ID_KEY, "search");
            context.put(FilterConstants.REQUEST_URI_KEY, "/search/2");
        }

        return null; }}Copy the code

Write the business logic in the run method

@Override
public Object run(a) throws ZuulException {
    // 1. Obtain Request
    RequestContext context = RequestContext.getCurrentContext();
    HttpServletRequest request = context.getRequest();
    // 2. Obtain the parameter redisKey
    String redisKey = request.getParameter("redisKey");

    // 3
    if(redisKey ! =null && redisKey.equalsIgnoreCase("customer")) {// http://localhost:8080/customer/1
        context.put(FilterConstants.SERVICE_ID_KEY, "customer-v1");
        context.put(FilterConstants.REQUEST_URI_KEY, "/customer/1");

    }else if(redisKey ! =null && redisKey.equalsIgnoreCase("search")) {// http://localhost:8081/search/2
        context.put(FilterConstants.SERVICE_ID_KEY, "search");
        context.put(FilterConstants.REQUEST_URI_KEY, "/search/2");
    }

    return null;
}
Copy the code

3, test,

7. Multilingual support -Sidecar

7.1 the introduction

In the SpringCloud project, you need to access some non-java applications, third-party interfaces, and cannot access Eureka, hystrix, feign, and other components. Start a proxy microservice that communicates with non-java applications or third-party interfaces, and use the proxy microservice to access relevant components of SpringCloud.

7.2 sidecars implementation

1. Create third-party services

Create a SpringBoot project and add a ControllerCopy the code

2. Create Maven project (06-sidecar) and change it to SpringBoot project

3. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-netflix-sidecar</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>
Copy the code

4. Add annotations

@EnableSidecar
Copy the code

5. Write a configuration file

server:
  port: 81

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

Specify the service name
spring:
  application:
    name: oter-service

# Specify the proxy's third party service
sidecar:
  port: 7001

Copy the code

6. Invoke third-party services through Customer through Feign

Service message passing -Stream

8.1 the introduction

A Stream encapsulates a message queue to make it easier to manipulate MQ message queues (streams only support Kafka and RabbitMQ).

8.2 Stream Quick Start

1. Start RabbitMQ

2. Consumer-import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
Copy the code

3. Consumer-profile

spring:
  # connect the RabbitMQ
  rabbitmq:
    host: 192.16875.139.
    port: 5672
    username: test
    password: test
    virtual-host: /test
Copy the code

4. Consumers – Listen to queues

public interface StreamClient {
    @Input("myMessage")
    SubscribableChannel input(a);
}
//------------------------------------
@Component
@EnableBinding(StreamClient.class)
public class StreamReceiver {
    @StreamListener("myMessage")
    public void msg(Object msg) {
        System.out.println("Received message:"+ msg); }}Copy the code

Producer-import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
Copy the code

6. Producer-profile

spring:
  # connect the RabbitMQ
  rabbitmq:
    host: 192.16875.139.
    port: 5672
    username: test
    password: test
    virtual-host: /test
Copy the code

7. Producers – Post messages

public interface StreamClient {
    @Output("myMessage")
    MessageChannel output(a);
}
//---------------------------------------
// Add annotations to the bootstrap class
@EnableBinding(StreamClient.class)
//---------------------------------------
@RestController
public class MessageController {
    @Autowired
    private StreamClient streamClient;

    @GetMapping("/send")
    public String send(a) {
        String msg = "Hello Stream!!!";
        boolean send = streamClient.output().send(MessageBuilder.withPayload(msg).build());
        return "Message sent successfully!!"; }}Copy the code

8.3 Repeated consumption of Stream

All you need to do is add a configuration that specifies the consumer group

spring:
  cloud:
    stream:
        bindings:
          myMessage: 		# queue name
            group: customer # Consumer Group
Copy the code

Consumer manual ACK of 8.4 Stream

1. Write the configuration

spring:
  cloud:
    stream:
        rabbit:
          bindings:
            myMessage:
              consumer:
                acknowledgeMode: MANUAL
Copy the code

2. Modify the methods on the consumer side

@StreamListener("myMessage")
public void msg(Object msg,
                @Header(name = AmqpHeaders.CHANNEL) Channel channel,
                @Header(name = AmqpHeaders.DELIVERY_TAG) Long deliveryTag) throws IOException {
    System.out.println("Received message:" + msg);
    channel.basicAck(deliveryTag, false);
}
Copy the code

Dynamic configuration of the service -Config

9.1 the introduction

1. Configuration files are scattered in different projects, which is inconvenient to maintain

2. Security of configuration files

3. The modified configuration file does not take effect immediately

9.2 set up the Config – Server

1. Create a Maven project and change it to SpringBoot

2. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code

3. Add annotations

@SpringBootApplication
@EnableConfigServer
Copy the code

4. Write configuration files (Git operations)

spring:
  application:
    name: CONFIG
  cloud:
    config:
      server:
        git:
          basedir: D:\basedir # local warehouse address
          username: jinshengwang
          password: jin6150090
          uri: https://gitee.com/jinshengwang/config-resp.git
Copy the code

5. Test (http://localhost:port/{label}/{application}-{profile}.yml)

9.3 Modifying Customer Connection Config

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
Copy the code

2. Write a configuration file

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

spring:
  application:
    name: CUSTOMER-${version}
  cloud:
    config:
      discovery:
        enabled: true
        service-id: CONFIG
      profile: dev

version: v1

# CONFIG - CUSTOMER-v1-dev.yml

Copy the code

3. Change the configuration name

Modified to bootstrap. Yml
Copy the code

4, test, release to the RabbitMQ (http://localhost:8080/send)

9.4 Dynamic Configuration

9.4.1 Implementation Principle

9.4.2 Service Connection to RabbitMQ

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
Copy the code

2. Write a configuration file to connect RabbitMQ information

spring:
  rabbitmq:
    host: 192.16875.139.
    port: 5672
    username: test
    password: test
    virtual-host: /test
Copy the code

9.4.3 Manual Refresh

1. Import dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code

2. Write a configuration file

management:
  endpoints:
    web:
      exposure:
        include: "*"

Copy the code

3. Add a Controller for Customer

@RefreshScope
public class CustomerController {
    @Value("${env}")
    private String env;
    
    @GetMapping("/env")
    public String env(a){
        returnenv; }}Copy the code

4, test,

1. After Gitee changes the CONFIG, the latest configuration information is automatically pulled up. 2. Other modules need to be updated, manually send a request to http://ip:10000/actuator/bus-refresh, not restart the project, you can get the latest configuration information.Copy the code

9.4.4 Intranet Penetration

1. Intranet penetration software official website: natapp.cn

2. Register and log in

3. Buy a free pass

4. Download the client, create config.ini file, copy the memory, and set the authToken value

5. Start the exe file and access the Config interface using the test domain name

9.4.5 Automatic Refresh

1. Configure WebHooks in Gitee

Add a filter to Config

Add WebHooksFilter to solve the problem that Gitlab Webhook triggers configuration center /actuator/bus-refresh requests return 400 error codesCopy the code

3, test,

10. Service tracking -Sleuth

10.1 the introduction

In the whole micro-service architecture, there are many micro-services, and a request may need to call multiple micro-services to complete a function. If problems occur in this process, what are the problems of so many services and what are the causes of the problems?

1. Sleuth can obtain the link information of the entire service.

2. Integrate Zipkin to view information through graphical interface

Sleuth can store logs in a database.

10.2 Use of Sleuth

1. Import dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
Copy the code

2. Write a configuration file

logging:
  level:
    org.springframework.web.servlet.DispatcherServlet: DEBUG
Copy the code

3, test,

SEARH: service name 36e7... : Total link ID ECa8... : link ID of the current service True: logs will be exported persistently. If the value is false, current logs will not be exported to other systems.Copy the code

10.3 Use of Zipkin

1. Build Zipkin web project, official website: zipkin.io/

version: '3.1'
services:
  zipkin:
    image: Openzipkin/zipkin: 2.12
    restart: always
    container_name: zipkin
    ports:
      - 9411: 9411
Copy the code

The spring-cloud-starter-sleuth package is used to replace the spring-cloud-starter-sleuth package

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
Copy the code

3. Write a configuration file

spring:
  sleuth:
    sampler:
      probability: 1 # What percentage of sleUTH information is output to zipkin
  zipkin:
    base-url: http://192.168.75.139:9411/
Copy the code

4, test,

10.4 to integrate the RabbitMQ

1. Import RabbitMQ dependencies

Spring-cloud-starter-zipkin has built-in RabbitMQ dependenciesCopy the code

2. Modify the configuration file

spring:
  zipkin:
    base-url: http://192.168.75.139:9411/
    sender:
      type: rabbit
Copy the code

3. Modify Zipkin information

version: '3.1'
services:
  zipkin:
    image: openzipkin/zipkin
    restart: always
    container_name: zipkin
    ports:
      - 9411: 9411
    environment:
      - RABBIT_ADDRESSES = 192.168.75.139
      - RABBIT_PASSWORD=test
      - RABBIT_USER=test
      - RABBIT_VIRTUAL_HOST=/test
Copy the code

4, test,

10.5 Zipkin stores data to ES

1. Re-modify Zipkin’s YML file

version: '3.1'
services:
  zipkin:
    image: openzipkin/zipkin
    restart: always
    container_name: zipkin
    ports:
      - 9411: 9411
    environment:
      - RABBIT_ADDRESSES = 192.168.75.139
      - RABBIT_PASSWORD=test
      - RABBIT_USER=test
      - RABBIT_VIRTUAL_HOST=/test
      - STORAGE_TYPE=elasticsearch
      - ES_HOSTS = http://192.168.75.139:9200
Copy the code

Note: Zipkin can’t be the latest version (I’ve retrofitted openZipkin/Zipkin :2.12) or it won’t be compatible with ES6.5.4.

Complete SpringCloud architecture diagram

Xii. Pit filling

12.1 The Eureka node is not synchronized

When Eureka is started, it must be started one by one. After Eureka1 is started, Eureka2 must be started. Otherwise, the node information is not synchronized.

12.2 Zipkin integration with ES

At first I installed the latest version of Zipkin, ES was 6.5.4, but Zipkin couldn’t connect to ES. I rolled back Zipkin to version 2.12, and I was ready to integrate.