package com.zteits.charge.config; import com.zteits.charge.service.spi.CallBusinessInfoSpi; import com.zteits.charge.service.spi.CallStationInfoSpi; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 调用科林接口代理类,实现加密和签名 * *

⚠️ 这里**故意删掉了**老代码上的 {@code @ComponentScan}(无参数版),它不是「少了个配置」, * 而是合并单 Jar 时的一个坑,详见 AGENTS.md 坑 14: * *

无参数 {@code @ComponentScan} 扫的是**本类所在包** {@code com.zteits.charge.config}。 * 合并单 Jar 后,这个包名同时被**封闭 Jar**({@code zteits-parking-charge-spring-boot-starter}, * 源码不可改)占用,于是它会把那个 Jar 里的 {@code ChargeConfig} 一起扫进来注册成 * {@code @Configuration};而 {@code ChargeConfig} 自己又带 * {@code @ComponentScan("com.zteits.charge")},会再触发一整轮**不受启动类过滤器约束**的扫描, * 最终抛出 {@code BeanDefinitionOverrideException}({@code @Bean("chargeService")} 撞 * {@code @Component ChargeService})。 * *

删掉它是**零损失**的:启动类 {@code ParkingServerApplication} 的 * {@code @ComponentScan} 已经包含 {@code com.zteits.charge},本包下的 * {@code KeLinOkHttpHelper} 等组件本来就会被扫到(实测启动日志里它们由启动类那一轮扫描注册, * 后一轮重复扫描对已注册的同源 Bean 是空操作)。老工程 7 个 JVM 里 * {@code ChargeApplication} 同样扫 {@code com.zteits.charge},所以这一行在老工程里也是冗余的。 */ @Slf4j @Configuration @RequiredArgsConstructor public class CallKeLinServiceProxyConfiguration { private Lock lock = new ReentrantLock(); final KeLinOkHttpHelper keLinOkHttpHelper; @Bean @ConditionalOnMissingBean public CallStationInfoSpi getStationService(){ return (CallStationInfoSpi) Proxy.newProxyInstance( CallKeLinServiceProxyConfiguration.class.getClassLoader(), new Class[] { CallStationInfoSpi.class }, new ChargingInvocationHandler() ); } @Bean @ConditionalOnMissingBean CallBusinessInfoSpi getBusinessService(){ return (CallBusinessInfoSpi) Proxy.newProxyInstance( CallKeLinServiceProxyConfiguration.class.getClassLoader(), new Class[] { CallBusinessInfoSpi.class }, new ChargingInvocationHandler() ); } @RequiredArgsConstructor public class ChargingInvocationHandler implements InvocationHandler{ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ApiName apiName = method.getAnnotation(ApiName.class); return keLinOkHttpHelper.post(apiName.value(),(String)args[0], args[1], method.getReturnType()); } } }