Springboot集成nacos与RestTemplate

一、背景及目的

springBoot要做成微服务,有很多解决方案,这里采用nacos与restTemplate方式,nacos作为springBoot的注册与发现中心,restTemplate作为具体的调用代理,这样可以快速的组合一个微服务系统。

二、实验环境及设计思路

springBoot  2.1.1 + jdk1.8 + nacos2.3.2 

Nacos Server 下载 | Nacos 官网,安装也请看官网,非常简单。

nacos集成springBoot参考:

Nacos 融合 Spring Cloud,成为注册配置中心 | Nacos

设计思路简图:

本地启动两个echoService服务提供者 ,端口号分别是8081和8082,向nacos注册。

本地启用1个服务调用者springBoot1,端口号为8080,向nacos注册,采用RestTemplate方式,并实现负载均衡的效果。

三、相关配置及代码

基本工程结构;

1、服务提供方echoService配置及代码

echoService 工程 pom.xml

<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.spell</groupId>
	<artifactId>echoServer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>echoServer</name>
	<description>echoServer</description>
	<url>http://maven.apache.org</url>


	<properties>
		<java.version>1.8</java.version>
		<maven.compiler.source>8</maven.compiler.source>
		<maven.compiler.target>8</maven.compiler.target>
		<skipTests>true</skipTests>
	</properties>


	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.1.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
			<version>2.1.1.RELEASE</version>
		</dependency>
	</dependencies>
</project>

echoService的application.yml 

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

application.properties配置 

server.port=8081
spring.application.name=echoService

server.servlet.context-path=/
server.tomcat.uri-encoding=UTF-8
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.com.spell=INFO
#logging.level.com.example.yourpackage=INFO
logging.file=./log/echoService.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

echoService的EchoController 

package com.spell.echoServer.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EchoController {
	@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
	public String echo(@PathVariable String string) {
		System.out.println("--receive request,name=" + string);
		return "Hello " + string;
	}
}

 echoService的Appliation.java, 这里加入了@EnableDiscoveryClient 注解

package com.spell;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;


@SpringBootApplication
@ComponentScan(basePackages = { "com.spell.*" })
@EnableDiscoveryClient
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
		System.out.println("====start up====");
	}
}

 2、调用方springBoot的配置

pom.xml与echoService类似,新增加一个httpclient的依赖

<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.spell</groupId>
	<artifactId>echoServer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>echoServer</name>
	<description>echoServer</description>
	<url>http://maven.apache.org</url>


	<properties>
		<java.version>1.8</java.version>
		<maven.compiler.source>8</maven.compiler.source>
		<maven.compiler.target>8</maven.compiler.target>
		<skipTests>true</skipTests>
	</properties>


	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.1.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
			<version>2.1.1.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.13</version>
		</dependency>
	</dependencies>
</project>

application.properties配置

server.port=8080
spring.application.name=sprintBoot1
server.servlet.context-path=/
server.tomcat.uri-encoding=UTF-8
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.com.spell=INFO
#logging.level.com.example.yourpackage=INFO
logging.file=./log/springboot.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

application.yaml配置

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

http:
  maxTotal: 50        #最大连接数
  defaultMaxPerRoute: 5  #并发数
  connectTimeout: 1000   #创建连接的最长时间
  connectionRequestTimeout: 500  #从连接池中获取到连接的最长时间
  socketTimeout: 10000 #数据传输的最长时间
  staleConnectionCheckEnabled: true  #提交请求前测试连接是否可用
  validateAfterInactivity: 3000000   #可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间,如果超过,释放socket重新建立

config/RestTemplatetConfig.java 用于配置httpClient线程池及LoadBlanced能力。

package com.spell.config;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplatetConfig {

	@Value("${http.maxTotal}")
	private Integer maxTotal;

	@Value("${http.defaultMaxPerRoute}")
	private Integer defaultMaxPerRoute;

	@Value("${http.connectTimeout}")
	private Integer connectTimeout;

	@Value("${http.connectionRequestTimeout}")
	private Integer connectionRequestTimeout;

	@Value("${http.socketTimeout}")
	private Integer socketTimeout;

	@Value("${http.staleConnectionCheckEnabled}")
	private boolean staleConnectionCheckEnabled;

	@Value("${http.validateAfterInactivity}")
	private Integer validateAfterInactivity;

	@Bean
	@LoadBalanced //增加负载均衡的能力
	public RestTemplate restTemplate() {
		return new RestTemplate(httpRequestFactory());
	}

	@Bean
	public ClientHttpRequestFactory httpRequestFactory() {
		return new HttpComponentsClientHttpRequestFactory(httpClient());
	}

	@Bean
	public HttpClient httpClient() {
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory())
				.register("https", SSLConnectionSocketFactory.getSocketFactory()).build();
		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
		connectionManager.setMaxTotal(maxTotal); // 最大连接数
		connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); // 单个路由最大连接数
		connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout) // 服务器返回数据(response)的时间,超过抛出read
																								// timeout
				.setConnectTimeout(connectTimeout) // 连接上服务器(握手成功)的时间,超出抛出connect timeout
				.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled) // 提交前检测是否可用
				.setConnectionRequestTimeout(connectionRequestTimeout)// 从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException:
																		// Timeout waiting for connection from pool
				.build();

		// headers
		List<Header> headers = new ArrayList<>();
		headers.add(new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
		headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
		headers.add(new BasicHeader("Accept-Language", "zh-CN"));
		headers.add(new BasicHeader("Connection", "Keep-Alive"));
		headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));

		return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager)
				.setDefaultHeaders(headers)
				// 保持长连接配置,需要在头添加Keep-Alive
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
				// 重试次数,默认是3次,没有开启
				.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true)).build();
	}

}

 EchoController.java,采用restTemplate来调用远程服务,注意访问的URL地址为服务注册名http://echoService/echo,这个具体在底层执行访问的时候,会替换为轮询的具体服务提供方的ip端口与地址。

package com.spell.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class EchoController {
	private final RestTemplate restTemplate;

	@Autowired
	public EchoController(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}

	@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
	public String echo(@PathVariable String str) {
		return restTemplate.getForObject("http://echoService/echo/" + str, String.class);
	}
}

Application.java 

package com.spell;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;


@SpringBootApplication
@ComponentScan(basePackages = { "com.spell.*" })
@EnableDiscoveryClient
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
		System.out.println("====start up====");
	}
}

四、测试结果

echoService的server.port分别为8081和8082各启动一次。

springBoot1工程server.port为8080启动一次,可以看到nacos的注册的服务:

访问:http://localhost:8080/echo/jack1,可以得到预期输出

可以看到echoService的具体输出,这样就完成了微服务基本的RPC调用及负载均衡能力了。 

 

五、结束语

SpringBoot这套微服务集成框架,还是非常方便的,如果性能要求不是特别高,可以采用这个框架,如果对性能的要求很高,建议用springboot + dubbo也是个不错的选择,不过最终还是要以压测对比为准。

欢迎大家点赞、收藏、订阅,你们的反馈是我持续输出的动力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值