聊聊 Http 服务化改造实践

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

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

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

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

1.什么是 Feign

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

2.快速入门实例

2.1 定义客户端

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

 
   com.netflix.feign
   feign-core
   8.18.0
 

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

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

@FeignClient
public interface HelloControllerApi {
 @RequestLine("GET /api/hello?name={name}")
 String hello(@Param(value = "name") String name);
}

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

public class HelloControllerApiTest {

 private HelloControllerApi service;

 @Before
 public void before(){
  service = Feign.builder()
    .options(new Request.Options(1000, 3500))
    .retryer(new Retryer.Default(5000, 5000, 3))
    .target(HelloControllerApi.class, "http://127.0.0.1:8080");
 }
 @Test
 public void hello(){
        // 调用http://127.0.0.1:8080/api/hello?name=world 的http接口
  System.out.println(service.hello("world"));
 }

}

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

2.3 定义服务端

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

@Controller
@RequestMapping(value = "api")
public class HelloController {
 @RequestMapping(value = "/hello", method = {RequestMethod.GET})
 @ResponseBody
 public String list(@RequestParam String name) {
  return "Hello " + name;
 }
}

//启动类
@SpringBootApplication(scanBasePackages = {"com.vhicool.manager"})
public class ManagerApplication {
 public static void main(String[] args) {
  SpringApplication.run(ManagerApplication.class, args);
 }
}

3.实现签名校验

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

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

public class AuthRequestInterceptor implements feign.RequestInterceptor {
 private TokenService tokenService;

 public AuthRequestInterceptor(TokenService tokenService) {
  this.tokenService = tokenService;
 }

 @Override
 public void apply(RequestTemplate template) {
  template.header("token", tokenService.getToken());
 }

}

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

public class FeignConfiguration {
  @Bean
 public RequestInterceptor authRequestInterceptor(ResourceIdentity resourceIdentity) {
  AuthRequestInterceptor authRequestInterceptor = new AuthRequestInterceptor(resourceIdentity);
  authRequestInterceptor.setErrorEncodeType(errorEncodeType);
  return authRequestInterceptor;
 }
}

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

@Component
public class AuthFilter implements Filter {

 @Autowired
 private TokenService tokeService;

 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  String remoteToken = ((HttpServletRequest) servletRequest).getHeader("token");
  if(!tokeService.valid(token)) {
      //异常处理逻辑
      return;
    }
  filterChain.doFilter(servletRequest, servletResponse);
 }
}

4.服务端自动生成 Feign

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

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

聊聊 Http 服务化改造实践_第1张图片

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

聊聊 Http 服务化改造实践_第2张图片

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

4.1 提取公共 API

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

 
        
            org.springframework.boot
            spring-boot-starter-web
        
    

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

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

4.2 服务端实现公共 API

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

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

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

@Controller
@RequestMapping
public class UserController implements IUserController {
 @Override
 @ResponseBody
 public List listAll(String name) {
  ArrayList list = new ArrayList<>();
  list.add("达菲");
  list.add("olu");
  list.add(name);
  return list;
 }
}

4.3 客户端实现公共 API

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


         
            org.springframework.cloud
            spring-cloud-starter-openfeign
            2.1.5.RELEASE
        
        
            junit
            junit
            4.12
            compile
        
         
            com.vhicool
            feign-api
            1.0-SNAPSHOT
            compile
        

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

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

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

@SpringBootApplication
@EnableFeignClients
public class ManagerApplication {
 public static void main(String[] args) {
  SpringApplication.run(ManagerApplication.class, args);
 }
}

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

@Configuration
public class FeignConfiguration {
 /**
  * 请求超时时间
  * @return
  */
 @Bean
 public Request.Options options() {
  return new Request.Options(2000, 3500);
 }
  //拦截器等定义
}

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

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {
 @Autowired
 private UserApi userApi;

 @Test
 public void listAll() {
  System.out.println(userApi.listAll("饼饼"));
 }
}

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

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

你可能感兴趣的:(C++Linux后端,http,网络协议,网络,C++服务器开发,服务器,linux)