系统集成Nacos和Feign

nacos 是用于构建、交付和管理微服务的平台,支持服务发现与配置管理。

Feign 是 Java 语言的 HTTP 客户端,通过接口与注解的方式来创建一个 Feign。

引入依赖

因为nacos默认使用的均衡负载组件为ribbon,而OpenFeign最新版本默认使用的是spring cloud loadbalancer,所以我们需要排除ribbon依赖,并引入spring cloud loadbalancer依赖。

因为nacos支持配置管理,所以需要引入spring cloud starter bootstrap依赖。

<!-- pom.xml -->
<properties>
	<java.version>1.8</java.version>
	<spring.boot.version>2.4.2</spring.boot.version>
	<spring.cloud.version>3.0.1</spring.cloud.version>
</properties>
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
		<version>${spring.boot.version}</version>
	</dependency>
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		<version>2021.1</version>
		<exclusions>
			<!--//丢弃ribbon-->
			<exclusion>
				<groupId>com.netflix.ribbon</groupId>
				<artifactId>ribbon</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
		<version>${spring.cloud.version}</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-bootstrap</artifactId>
		<version>${spring.cloud.version}</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-loadbalancer</artifactId>
		<version>${spring.cloud.version}</version>
	</dependency>
</dependencies>

在使用nacos时需要注意nacos及其依赖的版本。

  1. 通过依赖分析,发现nacos的2021.1版本引入的spring cloud版本为3.0.1,所以openfeign、bootstrap、loadbalancer等spring cloud组件的版本也需要为3.0.1。版本不符合的话会因冲突而报错。
  2. 因为nacos的2021.1版本支持的spring boot版本为2.4.2,所以引入的spring boot组件的版本也需要为2.4.2。具体版本可查看版本说明

集成nacos和feign时报错java.lang.ClassNotFoundException: org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties

今天在尝试集成nacos和feign时,报错: java.lang.ClassNotFoundException: org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties

通过idea的Add Maven dependency功能,发现这个类位于 spring-cloud-commons包内。

但是通过解压所引入的spring-cloud-commons的jar包,发现是存在该类的。

所以猜测可能是版本问题。

SpringBoot项目的配置文件中设置server.port不生效

我的配置文件为:

# application.yml
server:  
  port: 8081  
spring:  
  application:  
    name: test  
    cloud:  
      nacos:  
        discovery:  
          server-addr: http://localhost:8848

设置了 server.port不生效的原因是因为没有引入nacos依赖,但是却写上了nacos的配置,所以删掉nacos的配置即可。

修改后的配置文件:

# application.yml
server:  
  port: 8081  
spring:  
  application:  
    name: test 

如果需要使用nacos,在application.yml文件中配置server.port的话,会发现配置不生效。这个时候需要新建一个空白的application.properties文件,来使的application.yml文件中的server.port配置生效。原因未知。

RestTemplate发起HTTPS请求

因为发起HTTPS请求时需要验证服务端SSL证书,所以在此有两种解决办法,一是导入证书,二是忽略证书的校验。

在此我采用的是忽略证书的校验。

首先使用 RestTemplateBuilder来构建一个 RestTemplate,而非使用默认。requestFactory()方法用来设置 ClientHttpRequestFactorySimpleClientHttpRequestFactory是Spring内置的默认实现,实现了 ClientHttpRequestFactory接口,我们需要重写其 prepareConnection()方法,在此方法里实现对 HttpURLConnection的重新处理,忽略对证书的校验。

代码:

public class HttpsClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        try {
            if (connection instanceof HttpsURLConnection) {// https协议,修改协议版本
                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                // 信任任何链接,忽略对证书的校验
                TrustStrategy anyTrustStrategy = (x509Certificates, s) -> true;
                //自定义SSLContext
                SSLContext ctx = SSLContexts.custom().loadTrustMaterial(trustStore, anyTrustStrategy).build();
                // ssl问题
                ((HttpsURLConnection) connection).setSSLSocketFactory(ctx.getSocketFactory());
                //解决No subject alternative names matching IP address xxx.xxx.xxx.xxx found问题
                ((HttpsURLConnection) connection).setHostnameVerifier((s, sslSession) -> true);
                HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
                super.prepareConnection(httpsConnection, httpMethod);
            } else { // http协议
                super.prepareConnection(connection, httpMethod);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
    
String url = "https://xxx.xxx.xxx";
RestTemplate restTemplate = new RestTemplateBuilder()
		.requestFactory(HttpsClientHttpRequestFactory::new)
		//basic认证
		.basicAuthentication("username", "password")
		.build();
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
String str = response.getBody();
System.out.println(str);
    

注:

  1. RestTemplateBuilder 需要直接构建成 RestTemplate对象,而不能中间生成 RestTemplateBuilder对象。

Java集合-栈

栈是一种先进后出的数据结构,在Java中对应的接口为 DequeStack接口已经不建议使用。Deque接口继承自Queue接口,实则为双端队列,支持两端元素的插入、删除与访问。 Deque的方法有:

首端操作:

抛出异常 返回特殊值
查看 getFirst() peekFrist()
插入 addFirst() offerFirst()
删除 removeFirst() pollFirst()

尾端操作:

抛出异常 返回特殊值
查看 getLast() peekLast()
插入 addLast() offerLast()
删除 removeLast() pollLast()

栈方法对应的 Deque方法:

栈方法 Deque方法
查看 peek() peekFirst()
插入 push() addFirst()
删除 pop() removeFirst()

Deque主要实现类有:

使用例子:

Deque<Integer> deque=new LinkedList<>();
deque.push(1);
deque.peek();
deque.pop();