外观
yidun-private-custom — 私有化中间件凭据下发的定制服务
分层:私有化/集成适配层 | 部署单元:1 个(
facade/http-api-pwd) | 数据库:无(显式排除数据源自动装配) | base image:private-registry.nis.netease.com/library/base-image:jdk17(tagbase-250409)
一、模块定位与架构
模块面向私有化交付中「不同客户要用不同数据库/ES/Redis/ZooKeeper 账号密码」的诉求:对外提供一个取得中间件凭据的 HTTP 接口,内部按配置选择「默认空实现 / 配置解密实现 / 工行定制实现」之一。
它不连数据库、不依赖 Apollo 和 Dubbo,是典型的「按客户定制 + 运行时切换实现」的小服务;主要运维风险在实现选择(enable.credential.service)与密钥/解密工具是否就位。
架构分层
- 入口层:
facade/http-api-pwd(HttpPwdApplication+CredentialControllerPOST /api/agent/credential) - 配置层:
FacadeHttpConfiguration、CredentialExtendConfig(@ConfigurationProperties("credential.encrypt.extend")) - 业务层:
service/business(ServiceConfiguration+ 本地缓存CacheConfiguration) - 实现层:
DefaultCredentialServiceImpl(@Service("default"))、EncryptCredentialServiceImpl(@Service("encrypt"))、GongHangCredentialServiceImpl(@Service("gonghang")) - 支撑:
common、domain、service/base(MapperConfiguration空转,无 mapper)
关键数据流
- 上游以
POST /api/agent/credential提交CredentialRequest(可选userKey查询参数) CredentialController读@Value("${enable.credential.service:default}")得到clientNameapplicationContext.getBean(clientName, CredentialService.class)按名字取实现(default/encrypt/gonghang)encrypt实现:mysql且带userKey→ 查CredentialExtendConfig.mysql;否则读credential.encrypt.{type}.username/passwordencrypt实现用AesUtils.decrypt(cipher, aesKey)解密,并写ConcurrentHashMap缓存gonghang实现请求工行密码服务credential.gonghang.url,再用ProcessBuilder执行lib/SM4Encrypt-1.0.jar解出密码default实现直接返回空CredentialResponse
二、可部署服务清单
| 部署单元目录 | artifactId | 镜像名 | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml/Helm |
|---|---|---|---|---|---|---|
facade/http-api-pwd | privatecustom-facade-http-pwd | antispam-privatecustom-http-api-pwd | 8081 | 凭据下发 HTTP 服务 | 有 | 否(仓库内无清单,外部流水线部署) |
说明:
common、domain、service/base、service/business为非部署库模块。buildAll.sh(GLOBAL_ENV=private)遍历find . -name build.sh,只命中facade/http-api-pwd/build.sh这一个。
有 build.sh 的 1 个单元:facade/http-api-pwd/build.sh(MODEL_NAME=facade/http-api-pwd、BUILD_ENV=private、DOCKER_IMAGE_NAME=antispam-privatecustom-http-api-pwd、DOCKER_IMAGE_TAG=base-250409)。
非部署库模块(不参与镜像构建):
common(工具类:AesUtil、JsonDiffKits等)、domain(package-info 占位)、service/base(MapperConfiguration空转)、service/business(ServiceConfiguration+CacheConfiguration+ OkHttp 组件)
三、同模块启动顺序
facade/http-api-pwd— 唯一单元,无同模块前置- (可选)若启用
enable.credential.service=gonghang:需先保证工行密码服务可达、lib/SM4Encrypt-1.0.jar已放入容器工作目录,再启动本服务
理由:模块内无其它可启动单元,且实现靠运行时属性选择,无编译期/启动期依赖链,顺序仅由外部依赖决定。
四、逐服务启动逻辑
facade/http-api-pwd
- 启动类:
com.netease.yidun.privatecustom.facade.http.HttpPwdApplication(facade/http-api-pwd/src/main/java/.../HttpPwdApplication.java) - 注解:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration, DataSourceTransactionManagerAutoConfiguration, MybatisAutoConfiguration})——显式不连数据库 @EnableAspectJAutoProxy- 无
@EnableApolloConfig、无@EnableDubbo @Import的 Configuration:FacadeHttpConfiguration(同包configuration/)@Import({ServiceConfiguration, MapperConfiguration, CacheConfiguration})@Bean validator()(Hibernate,hibernate.validator.fail_fast=false)ServiceConfiguration(service/business/.../service/):@Configuration+@MapperScan("com.netease.yidun.privatecustom.business.service")MapperConfiguration(service/base/.../mapper/config/):@Configuration+@MapperScan("com.netease.yidun.privatecustom.mapper")(该包下无 mapper/entity,扫描空转)CacheConfiguration:@EnableCaching+@ConditionalOnProperty(value="privatecustom.cache.enable", havingValue="true")+@EnableConfigurationProperties(LocalCacheProperties),建 CaffeineCacheManager
- 其它
@Configuration:CredentialExtendConfig(@ConfigurationProperties("credential.encrypt.extend"),Map<String, MysqlCredential> mysql) - 控制器:
CredentialController(@RestController+@RequestMapping("/api/agent"),@PostMapping("/credential"),@Resource ApplicationContext);另有GlobalExceptionHandler - 各实现带
@PostConstruct:DefaultCredentialServiceImpl.init()→ 打印Default credential service initEncryptCredentialServiceImpl.init()→aesKey为空时兜底DEFAULT_AES_KEY_BASE64GongHangCredentialServiceImpl.init()→ 打印url/token/username/config/decryptJarName(mockData非空时额外打印)
main():仅SpringApplication.run(...),无自定义;启动钩子:无 Runner/Listener- 配置:
spring.main.allow-circular-references=true、server.port=8081、spring.application.name=yidun-private-custom_http-api-pwd
三种凭据实现对照
| bean 名 | 实现类 | 生效条件 | 数据来源 |
|---|---|---|---|
default | DefaultCredentialServiceImpl | 未配置 enable.credential.service(默认) | 无,返回空 CredentialResponse |
encrypt | EncryptCredentialServiceImpl | enable.credential.service=encrypt | credential.encrypt.{type}.*、credential.encrypt.extend.mysql.* |
gonghang | GongHangCredentialServiceImpl | enable.credential.service=gonghang | 工行密码服务 + lib/SM4Encrypt-1.0.jar |
五、启动前置依赖
| 依赖 | 配置键/地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| 无 Apollo | pom 无 apollo-client | — | — |
| 无 ZooKeeper / Dubbo | pom 无 dubbo、zookeeper 依赖 | — | — |
| 无数据库 | @SpringBootApplication(exclude=...) 排除数据源与 MyBatis 自动装配 | — | — |
| 无 Redis / ES / Kafka | pom 无相关 starter | — | — |
工行密码服务(仅 gonghang) | credential.gonghang.url、credential.gonghang.token、credential.gonghang.config、credential.gonghang.username、credential.gonghang.mockData | 弱依赖(不选 gonghang 时不触发) | application.properties |
SM4 解密 jar(仅 gonghang) | credential.gonghang.decryptJarName=SM4Encrypt-1.0.jar,路径 System.getProperty("user.dir")/lib/<jar>;执行 java.home/bin/java | 弱依赖(仓库内未提供该 jar,file/lib/ 下仅 sentry jar) | 容器工作目录 |
六、启动参数与 Profile
-Dspring.profiles.active:application.properties默认dev;Dockerfile 的JAVA_OPTS覆盖为private- Maven profile(根 pom 显式定义):
default(activeByDefault,deploy.env=default)、test(deploy.env=test)、online(deploy.env=online)、private(deploy.env=private) - 构建:
buildAll.sh的GLOBAL_ENV=private,命中facade/http-api-pwd/build.shBUILD_ENV=private、DOCKER_IMAGE_NAME=antispam-privatecustom-http-api-pwd、DOCKER_IMAGE_TAG=base-250409、DOCKER_REPOSITORY=private-registry.nis.netease.com/yidunmvn clean install --pl facade/http-api-pwd -am -T 1C -U -Dmaven.test.skip=true -P private(不带-Dcustom.finalName,因 pom 硬编finalName=antispam-privatecustom-http-api-pwd)docker buildx build --pull --platform linux/amd64,linux/arm64 --push后podupdate.sh
JAVA_OPTS:-Xmx512m -Xms512m -XX:+UseG1GC -Dspring.profiles.active=private;ENTRYPOINT ["bash","docker-entrypoint.sh"]- 技术栈:Spring Boot
2.7.18、java.version=17、MyBatis-Flex1.9.4+mybatis-spring-boot-starter、spring-boot-starter-aop/web/actuator、qy-qos-web、sentry、Guava、Caffeine、disruptor - base image / 仓库:
private-registry.nis.netease.com/library/base-image:jdk17;构建仓库private-registry.nis.netease.com/yidun;tagbase-250409 - 日志与 filter:
log4j2.xml+log4j2/{console,file,kafka}-appender.xml;src/main/filter/{default,private}.properties
七、启动期踩坑
enable.credential.service默认为default,若客户环境未显式配置,接口会一直返回空凭据(DefaultCredentialServiceImpl返回new CredentialResponse()),看起来「服务正常但没有数据」。EncryptCredentialServiceImpl(@Service("encrypt"))与GongHangCredentialServiceImpl(@Service("gonghang"))都带@ConditionalOnProperty(..., matchIfMissing=false):若enable.credential.service与 bean 名不一致,applicationContext.getBean(clientName, ...)抛NoSuchBeanDefinitionException。GongHangCredentialServiceImpl.runToolJar()依赖System.getProperty("user.dir")/lib/SM4Encrypt-1.0.jar与java.home/bin/java(Windows 走java.exe);容器内缺该 jar 时不会启动报错,只有首次调用接口才抛IllegalStateException("Tool jar exit code: ...")。仓库file/lib/只放了 sentry jar,需自行补 SM4 jar。EncryptCredentialServiceImpl内置硬编码默认 AES keyWWlEdW4yMDI2U2VjcmV0IQ==(明文YiDun2026Secret!);未配credential.encrypt.aes.key时即用该默认值,生产需替换。- pom 同时引入
mybatis-flex-spring-boot-starter与mybatis-spring-boot-starter,但启动类 exclude 了数据源自动装配;若后续误加DataSource依赖或去掉 exclude,会因缺spring.datasource.url启动失败。 MapperConfiguration扫描的com.netease.yidun.privatecustom.mapper包下没有任何 mapper/entity,属空转;排查「mapper 未注册」时不要在此处找原因。spring.main.allow-circular-references=true已开启循环依赖兜底,说明存在循环引用;贸然去除该配置可能直接导致启动失败。credential.encrypt.{type}.username/password为空时EncryptCredentialServiceImpl.get()只打 warn 并返回空字段的CredentialResponse(不抛异常),上游可能把「空凭据」当成配置成功。EncryptCredentialServiceImpl的cache是static ConcurrentHashMap,进程内永久缓存解密结果;改配置后需重启进程才能生效。GongHangCredentialServiceImpl的cache同样按request.getType()永久缓存;且credential.gonghang.mockData非空时直接返回 mock 值、完全绕过工行服务,上线前必须确认该值为空。CredentialController用@Resource ApplicationContext按名字取 bean:新增实现必须让 bean 名、enable.credential.service取值、@ConditionalOnProperty的havingValue三处保持一致。
八、跨模块前置
- 工行密码服务:仅
enable.credential.service=gonghang时依赖其 HTTP 服务与本地解密 jar(弱依赖) - 基础设施:无(不依赖 Apollo、ZK、Dubbo、MySQL、Redis、ES、Kafka)
- 上游调用方:自定义平台/交付脚本按
enable.credential.service与credential.encrypt.*约定配置后调用/api/agent/credential - 与易盾其余模块关系:无 Dubbo/消息耦合,凭据值仅作数据由上游自行使用