Bootstrap

AOP实现上下游泳道隔离RPC调用

在平时代码项目代码测试的过程中,“隔离”思想就经常被用上,比方说多个并行开发的需求都需要用到服务 A 的能力,但是又需要同时部署 A 不同的代码分支,这个时候“泳道隔离”机制就显得尤为重要了。“泳道隔离”即将相同代码仓库的不同代码分支部署到不同的泳道环境中,代码分支的上下游也可以部署到相同的泳道环境中,我们通过指定对应的泳道环境标就可以将请求打到不同的环境中,真正实现代码隔离,提高程序员并行开发的效率。

但是存在这样一种场景,在基准泳道环境 env_a 上部署了一个项目 project_1,但是我并不想让 project_1 直接调用其在 env_a 中部署好的下游服务 project_2,我反倒想让它 “复用” 另一个泳道环境,泳道环境比方说 env_b 中的 project_2,这个时候就可以在 java 启动项目时的环境变量中动态指定,从而实现“跨泳道”的调用。本文就是想记录下我们如何通过 AOP 机制实现这种跨泳道的泳道环境标设置,具体的跨调用原理可以理解为 泳道基建可以根据设置的环境标帮我们做请求的转发。

主要是复习下 AOP 的用法

  1. 环境依赖搭建
<?xml version="1.0" encoding="UTF-8"?>
<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.jxz</groupId>
    <artifactId>AOP_RPC</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

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

</project>
  1. 注解和切面相关

注解

package com.jxz.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/11/16
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ThriftEnv {
    String environmentVariable();
}


切面

package com.jxz.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/11/16
 */
@Aspect
@Component
@Slf4j
public class ThriftEnvAspect {


    @Pointcut("@annotation(com.jxz.aop.ThriftEnv)")
    public void pointCut() {

    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        Class<?> targetClass = jp.getTarget().getClass();
        log.info("目标类 = {}", targetClass);
        MethodSignature ms = (MethodSignature) jp.getSignature();
        log.info("目标方法签名 = {}", ms);
        Method method = targetClass.getMethod(ms.getName(), ms.getParameterTypes());
        log.info("目标方法 = {}", method);

        ThriftEnv annotation = method.getAnnotation(ThriftEnv.class);
        String env = annotation.environmentVariable();
        log.info("切换到目标泳道 = {}", env);

        return jp.proceed();
    }
}
  1. 调用下游 RPC 时使用注解
package com.jxz.adapter;

import com.jxz.aop.ThriftEnv;
import org.springframework.stereotype.Service;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2024/11/16
 */
@Service
public class AuthAdapter {

    @ThriftEnv(environmentVariable = "auth_thrift_env")
    public String queryAuth(String name) {
        return name + "_auth";
    }
}
  1. 在启动项目的环境变量中指定下游的泳道环境

在这里插入图片描述

;