前言
笔者一直普及有关Go语言和容器Docker方面的技术,这两方面的技术都是入门和深入云原生技术的底层技术;作为云原生上层应用中java还是需求量最高的,在java的云技术里springcloud和springboot是java中顶级流量的两个框架,程序员紫龙在java微服务架构也折腾过很多年,今天给大家分享的就是有关springboot里有关Endponint使用的一个技术坑。
先简要的介绍一下Endpoint(端点) 首先endpoint是个很热的词,在很多架构,特别是有关云原生的产品和架构里都有endpoint这个词。springboot里的这个endpoint指的是SpringBoot通过web或者jmx的方式向外部暴露应用的信息,或者上下文的信息。
SpringCloud-Admin就是根据此技术来进行实现的。还有springboot里的actuator也都是有关endpoint的应用和架构;他们用到的技术就是@Endpoint。这些技术点可以开发更高级的SpringBoot应用(非业务系统)。在进行一些系统服务方面的开发和扩展基础架构的过程中经常使用的方式。今天就带大家一下来看看在进行Endpoint的系统开发中遇到的一个坑;
@Slf4j
@Endpoint(id = "feign-info")
@Component
public class FeignSampleEndpoint{
@ReadOperation
public FeignSampleState detailState(@Selector String[] paths){
FeignSampleState state = feignSampleState;
if(paths!=null){
Arrays.stream(paths).forEach( one-> {
state.getInfo().put(one , one );
});
}
return state;
}
}
上面这段代码, 实现了一个简单的ENDPOINT的自定义扩展,仅作为演示功能;
编译打包,运行, 就是不能访问,到达理想的效果, 代码检查来检查去,没有发现有什么代码问题; 开启调试功能, 就是不能进入这个代码片段, 既然没有进入这段代码,那么也就是这个Endpoint没有springboot的autoconfiguration自动的加载进来;
可是打开actuator, 查看Endpoint注册信息
在actuator里还是可以查看到这个endpoint的信息
"feign-info-args0": {
"href": "http://localhost:10087/actuator/feign-info/{args0}",
"templated": true
}
很明显,这个endpoint已经注册到BeanFactory里了,也不是注册上的问题。
"href": "http://localhost:10087/actuator/feign-info/{args0}",
URL也已经注册进去了,但是就是不能访问,应该还是注册哪里确实是有些问题。
实在是没有办法,最直接的方法,对着其他的系统的endpoint对比查看,发现问题在于
URL的注册方式不对; 按照其他的方式来套路的话,正确的URL注册应该为
"feign-info-paths": {
"href": "http://localhost:10087/actuator/feign-info/{*paths}",
"templated": true
}
对比一下,
1. 名称应该是feign-info-paths, 而不是feign-info-arg0
2. href里应该是{*paths} , 不是{args0}
这样一比较是不是,可以有点解决问题的灵感了。 你现在可以猜的出是哪里的问题了吗?
对着Endpoint定义的代码,其实差别就在于参数的名称是没有映射到这个信息里去了,问题就应该在这里的, java的反射是可以支持到参数名的,但是这里明显是有点问题的。 从这个方面去找问题的根源和解决方法。
在java 1.8以下几某些1.8低版本中编译出来的class是无法取到参数名的,会导致该接口使用失败,如果通过这些编译出来的class来获取指定的参数名,会达不到想要的效果。
java8中的新特性可以直接通过反射获取方法的参数名,
//通过类名获取class
Class clazz=Class.forName(className);
//通过方法名获取对应的方法
Method method=clazz.getDeclaredMethod(methodName);
//获取方法的所有参数
Parameter parameter=method.getParameters();
//获取第一个参数的名字
String paraName=parameter[0]getName();
但java编译时默认是关闭的,所以使用javac -parameters进行编译即可,
idea中找到File->Settings->java Compiler中的Additional command line parameters添加-parameters参数即可,
对应使用maven来构建项目的,在pom文件里,加入相关的设置即可
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>
重新打包,编译,发布,
实现即要的效果。
结束语
Java以面向对象和实现架构之美而受我的喜欢,在此两点上,java比go太优秀了, springboot和springcloud架构里的设计,把java语言的设计之美和架构之美更加完美的展示了, 大家可以多多关注一些类似于endpoint这样的基于架构上的一些实现代码,绝对比写CRUD要过瘾的多。要更有成就感。