• 聊聊Http服务化改造实践


    在微服务架构体系中远程RPC调用主要包括Dubbo与Http调用两个大类,由于Dubbo拥有服务注册中心,并且起服务的命名非常规范,使用包名.类名.方法名进行描述。

    而http调用通常都是使用httpclient等相关类库,这些在使用上并没有问题,但API都是分散在整个工程的各个地方,如果HTTP调用也可以使用类似Dubbo服务的表示方法,采用声明式定义就好了。

    在开源的世界中只有想不到,没有找不到,为了解决Feign的声明式服务化管理,Feign框架应运而生,本文主要介绍如何使用Feign实现Http服务声明化管理与调用。

    1.什么是Feign

    Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求。Feign通过注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,封装了http调用流程。

    2、快速入门实例

    2.1定义客户端

    首先要引入Feign的maven依赖,如下图所示:

    1. <dependency>
    2. <groupId>com.netflix.feign</groupId>
    3. <artifactId>feign-core</artifactId>
    4. <version>8.18.0</version>
    5. </dependency>

    2.2 定义服务调用API(类似Dubbo API)

    服务调用的API声明代码如下所示:

    1. @FeignClient
    2. public interface HelloControllerApi {
    3. @RequestLine("GET /api/hello?name={name}")
    4. String hello(@Param(value = "name") String name);
    5. }

    这里的要点是使用@FeignClient进行声明。声明后就可以通过HelloControllerApi进行远程HTTP调用,示例代码如下:

    1. public class HelloControllerApiTest {
    2. private HelloControllerApi service;
    3. @Before
    4. public void before(){
    5. service = Feign.builder()
    6. .options(new Request.Options(1000, 3500))
    7. .retryer(new Retryer.Default(5000, 5000, 3))
    8. .target(HelloControllerApi.class, "http://127.0.0.1:8080");
    9. }
    10. @Test
    11. public void hello(){
    12. // 调用http://127.0.0.1:8080/api/hello?name=world 的http接口
    13. System.out.println(service.hello("world"));
    14. }
    15. }

    当然需要在调用方的启动类上增加@EnableFeignClients(defaultConfiguration = FeignConfiguration.class)注解。

    2.3定义服务端

    服务端与Feign并无关系,主要按照API的方式实现即可,服务端实现代码如下所示:

    1. @Controller
    2. @RequestMapping(value = "api")
    3. public class HelloController {
    4. @RequestMapping(value = "/hello", method = {RequestMethod.GET})
    5. @ResponseBody
    6. public String list(@RequestParam String name) {
    7. return "Hello " + name;
    8. }
    9. }
    10. //启动类
    11. @SpringBootApplication(scanBasePackages = {"com.vhicool.manager"})
    12. public class ManagerApplication {
    13. public static void main(String[] args) {
    14. SpringApplication.run(ManagerApplication.class, args);
    15. }
    16. }

    3.实现签名校验

    上述只是简单实用Feign,接下来以实现签名校验为例展示Feign的扩展机制。

    签名验证是最常见的安全机制,首先在客户端定义一个签名拦截器,用于生成签名信息,示范代码如下图所示:

    1. public class AuthRequestInterceptor implements feign.RequestInterceptor {
    2. private TokenService tokenService;
    3. public AuthRequestInterceptor(TokenService tokenService) {
    4. this.tokenService = tokenService;
    5. }
    6. @Override
    7. public void apply(RequestTemplate template) {
    8. template.header("token", tokenService.getToken());
    9. }
    10. }

    并且在Feign的全局配置文件中创建对应的拦截器,示例代码如下:

    1. public class FeignConfiguration {
    2. @Bean
    3. public RequestInterceptor authRequestInterceptor(ResourceIdentity resourceIdentity) {
    4. AuthRequestInterceptor authRequestInterceptor = new AuthRequestInterceptor(resourceIdentity);
    5. authRequestInterceptor.setErrorEncodeType(errorEncodeType);
    6. return authRequestInterceptor;
    7. }
    8. }

    同时在服务端获取token并对token进行校验,示例代码如下:

    1. @Component
    2. public class AuthFilter implements Filter {
    3. @Autowired
    4. private TokenService tokeService;
    5. @Override
    6. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    7. String remoteToken = ((HttpServletRequest) servletRequest).getHeader("token");
    8. if(!tokeService.valid(token)) {
    9. //异常处理逻辑
    10. return;
    11. }
    12. filterChain.doFilter(servletRequest, servletResponse);
    13. }
    14. }

    4.服务端自动生成Feign

    上面的示例虽然实现了服务接口的声明式管理,但调用端、客户端并没有显示的约束关系,接下来展示如何使用客户端、服务端使用继承方式定义服务调用API。

    例如要实现如下图的效果:

    原生的Feign无法实现该效果,我们需要使用OpenFeign类库,两者之间的对比如下图所示:

    接下来详细介绍具体实现方法。

    4.1 提取公共API

    首先使用一个模块定义公共API,需要引入maven依赖,代码示例如下所示:

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-web</artifactId>
    5. </dependency>
    6. </dependencies>

    接下来定义公共的服务接口,客户端、服务端都需要实现该接口,公共服务端接口定义如下:

    1. public interface IUserController {
    2. @RequestMapping(value = "user/list-all", method = {RequestMethod.GET})
    3. List listAll(@RequestParam String name);
    4. }

    4.2 服务端实现公共API

    首先需要添加相应的maven依赖,代码如下:

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-web</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>com.vhicool</groupId>
    7. <artifactId>feign-api</artifactId>
    8. <version>1.0-SNAPSHOT</version>
    9. <scope>compile</scope>
    10. </dependency>

    服务端采用继承方式实现,具体代码如下所示:

    1. @Controller
    2. @RequestMapping
    3. public class UserController implements IUserController {
    4. @Override
    5. @ResponseBody
    6. public List<String> listAll(String name) {
    7. ArrayList<String> list = new ArrayList<>();
    8. list.add("达菲");
    9. list.add("olu");
    10. list.add(name);
    11. return list;
    12. }
    13. }

    4.3 客户端实现公共API

    客户端首先同样需要增加相应的依赖,具体代码如下所示:

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-openfeign</artifactId>
    4. <version>2.1.5.RELEASE</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>junit</groupId>
    8. <artifactId>junit</artifactId>
    9. <version>4.12</version>
    10. <scope>compile</scope>
    11. </dependency>
    12. <dependency>
    13. <groupId>com.vhicool</groupId>
    14. <artifactId>feign-api</artifactId>
    15. <version>1.0-SNAPSHOT</version>
    16. <scope>compile</scope>
    17. </dependency>

    客户端服务调用类需要继承公共API:

    1. @FeignClient(value = "user", url = "http://localhost:8080")
    2. public interface UserApi extends IUserController {
    3. }

    同时客户端启动类需要增加@EnableFeignClients注解,具体示例代码如下所示:

    1. @SpringBootApplication
    2. @EnableFeignClients
    3. public class ManagerApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(ManagerApplication.class, args);
    6. }
    7. }

    同样基于Springboot编程方式,可以为Feign配置全局参数,具体如下:

    1. @Configuration
    2. public class FeignConfiguration {
    3. /**
    4. * 请求超时时间
    5. * @return
    6. */
    7. @Bean
    8. public Request.Options options() {
    9. return new Request.Options(2000, 3500);
    10. }
    11. //拦截器等定义
    12. }

    接下来客户端就可以用如下方式进行调用:

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest
    3. public class UserControllerTest {
    4. @Autowired
    5. private UserApi userApi;
    6. @Test
    7. public void listAll() {
    8. System.out.println(userApi.listAll("饼饼"));
    9. }
    10. }

    当前项目编译的jar包,类也已经被替换成我们自定义的类,目标达成。


    用工具

    成功的前端工程师很会善用工具,这些年低代码概念开始流行,像国外的 Mendix,国内的 JNPF,这种新型的开发方式,图形化的拖拉拽配置界面,并兼容了自定义的组件、代码扩展,确实在 B 端后台管理类网站建设中很大程度上的提升了效率。

    开源地址:JNPF体验中心

    代码量少,系统的稳定性和易调整性都会得到一定的保障。基于代码生成器,可一站式开发多端使用 Web、Android、IOS、微信小程序。代码自动生成后可以下载本地,进行二次开发,有效提高整体开发效率。同时,支持多种云环境部署、本地部署给予最大的安全保障,可以快速搭建适合自身应用场景的产品。

  • 相关阅读:
    5.最长回文子串
    C++输入输出流2
    【服务器数据恢复】Zfs文件系统误删除数据的数据恢复案例
    文档的重要性及接口文档模板
    java学习之mybatis-plus
    本地python连接腾讯云数据库
    一文带你悉知JDBC
    自己动手写java虚拟机(第一话)
    mac IDEA激活 亲测有效
    spring boot中使用Bean Validation做优雅的参数校验
  • 原文地址:https://blog.csdn.net/sdasdas12/article/details/132606353