在平时代码项目代码测试的过程中,“隔离”思想就经常被用上,比方说多个并行开发的需求都需要用到服务 A 的能力,但是又需要同时部署 A 不同的代码分支,这个时候“泳道隔离”机制就显得尤为重要了。“泳道隔离”即将相同代码仓库的不同代码分支部署到不同的泳道环境中,代码分支的上下游也可以部署到相同的泳道环境中,我们通过指定对应的泳道环境标就可以将请求打到不同的环境中,真正实现代码隔离,提高程序员并行开发的效率。
但是存在这样一种场景,在基准泳道环境 env_a 上部署了一个项目 project_1,但是我并不想让 project_1 直接调用其在 env_a 中部署好的下游服务 project_2,我反倒想让它 “复用” 另一个泳道环境,泳道环境比方说 env_b 中的 project_2,这个时候就可以在 java 启动项目时的环境变量中动态指定,从而实现“跨泳道”的调用。本文就是想记录下我们如何通过 AOP 机制实现这种跨泳道的泳道环境标设置,具体的跨调用原理可以理解为 泳道基建可以根据设置的环境标帮我们做请求的转发。
主要是复习下 AOP 的用法
- 环境依赖搭建
<?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>
- 注解和切面相关
注解
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();
}
}
- 调用下游 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";
}
}
- 在启动项目的环境变量中指定下游的泳道环境