What is microservice? What is spring cloud?
Microservice is a kind of architecture pattern, which advocates to divide an application into many tiny services. Services and services coordinate and cooperate with each other. Each service running is an independent process, and lightweight communication mechanism is adopted between services and services. In short, it is to divide a huge and complex single application into n multiple micro services (one service is responsible for one business), and each micro service is deployed independently.
The difference between microservices and clusters is that each deployed service of microservices is different, while each deployed service of clusters is the same.
Spring Cloud is a microservice framework. Compared with RPC frameworks such as Dubbo, Spring Cloud provides a complete set of distributed system solutions. It is built on the basis of spring boot. Spring Cloud's five beasts are Eureka, Ribbon, Feign, Hystrix and Zuul.
Environment building
Version specification
springboot: 2.0.3
springcloud: Finchley
Create a parent project (maven project)
Select maven and click next
Then click Finish
Modify the parent project 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lzh</groupId> <artifactId>my-springcloud-01</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <!--<version>Dalston.SR1</version>--> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.0.4</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.31</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <finalName>microservicecloud</finalName> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <delimiters> <delimit>$</delimit> </delimiters> </configuration> </plugin> </plugins> </build> </project>
Create subproject (maven project)
Project Name: microservice-consumer-80
pom.xml file
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>my-springcloud-01</artifactId> <groupId>com.lzh</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>microservice-consumer-80</artifactId> <dependencies> <dependency> <groupId>com.lzh</groupId> <artifactId>microservice-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- integration ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> </project>
Encoding implementation
Add @ EnableDiscoveryClient annotation to the main startup class
Create a configuration file ConfigBean.java, new a RestTemplate remote call template, add @ LoadBalanced annotation, and enable load balancing
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author lzh * create 2019-11-05-9:58 */ @Configuration public class ConfigBean { @Bean //Add load balancing //Spring Cloud Ribbon is a set of client load balancing tools based on Netflix Ribbon @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
In the DeptServiceImpl.java class of the service layer, use the RestTemplate template tool to call. Here, use the service name to call. If the service name is the same, it will make a sequential polling call
import com.lzh.cloud.model.Dept; import com.lzh.cloud.service.DeptService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; /** * @author lzh * create 2019-11-05-10:27 */ @Service public class DeptServiceImpl implements DeptService { /** * Using restTemplate to access restful interface is very simple and crude. * (url, requestMap, ResponseBean.class)These three parameters represent * REST The object type to which the request address, request parameter, and HTTP response transformation are converted. */ @Autowired private RestTemplate restTemplate; //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT"; @Override public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class); } @Override public Dept get(Long id) { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class); } @Override public List<Dept> list() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list/", List.class); } @Override public Object discovery() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class); } }
Custom polling rules
Create a configuration MySelRule class in the previous package of the main startup class. Be careful not to create it in the same package as the main startup class or in the sub package of the main startup class
import com.netflix.loadbalancer.IRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author lzh * create 2019-05-19-17:10 */ @Configuration public class MySelfRule { @Bean public IRule myRule(){ //return new RandomRule(); //Ribbon is polling by default, and I customize it as random //Return new roundrobin rule(); / / ribbon is polling by default, and I define it as random return new RandomRule_LZH(); // I customize it five times for each machine } }
Refer to the source code, and customize the polling algorithm randomrule · lzh.java
import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import java.util.List; public class RandomRule_LZH extends AbstractLoadBalancerRule { // total = 0 / / when total = 5, we can move the pointer down, // index = 0 / / the address of the server currently providing external services, // total needs to be reset to zero, but it has reached 5 times. Our index = 1 // Analysis: we have five times, but there are only three microservices (8001, 8002, 8003), OK? // private int total = 0; // The total number of calls. Currently, each set is required to be called 5 times private int currentIndex = 0; // Machine number of the current service public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers(); List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { /* * No servers. End regardless of pass, because subsequent passes only get more * restrictive. */ return null; } // int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3); // server = upList.get(index); // private int total = 0; / / the total number of calls. At present, each set is required to be called 5 times // private int currentIndex = 0; / / the machine number of the current service if (total < 5) { server = upList.get(currentIndex); total++; } else { total = 0; currentIndex++; if (currentIndex >= upList.size()) { currentIndex = 0; } } if (server == null) { /* * The only time this should happen is if the server list were somehow trimmed. * This is a transient condition. Retry after yielding. */ Thread.yield(); continue; } if (server.isAlive()) { return (server); } // Shouldn't actually happen.. but must be transient or a bug. server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub } }
Finally, don't forget to annotate the main startup class and use the custom polling algorithm configuration = MySelfRule.class
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * @author lzh * create 2019-11-04-22:26 */ @SpringBootApplication @EnableEurekaClient //Custom load balancing rules //When the service is started, our custom Ribbon configuration class can be loaded to make the configuration effective //configuration = MySelfRule.class load the MySelfRule configuration class into the container @RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MySelfRule.class) @EnableDiscoveryClient public class MyConsumerApplication_80 { public static void main(String[] args) { SpringApplication.run(MyConsumerApplication_80.class); } }
Code
github: https://github.com/LZHDonald/my-springcloud-01/tree/master/microservice-consumer-80