You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中基于条件创建带双实现的自定义注解接口动态代理咨询

解决方案

1. 基础定义:自定义注解与目标类

先明确自定义注解标注接口、实现类实现该接口的结构:

// 自定义注解,标注需要代理的接口
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProxyTargetInterface {
}

// 被注解标注的业务接口
@ProxyTargetInterface
public interface UserService {
    void doBusiness();
}

// 接口的业务实现类
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void doBusiness() {
        System.out.println("执行原业务逻辑");
    }
}

2. 两种代理逻辑实现

(1)保留原逻辑的代理(支持增强)

基于JDK动态代理实现,可在原逻辑前后添加增强操作:

public class RetainLogicHandler implements InvocationHandler {
    private final Object targetBean;

    public RetainLogicHandler(Object targetBean) {
        this.targetBean = targetBean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 可选:添加前置增强(如日志、权限校验)
        System.out.println("代理前置增强");
        // 执行原业务逻辑
        Object result = method.invoke(targetBean, args);
        // 可选:添加后置增强
        System.out.println("代理后置增强");
        return result;
    }
}

(2)无业务逻辑的占位代理

直接返回默认值,不触发原业务逻辑:

public class PlaceholderLogicHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 根据返回值类型返回默认值
        Class<?> returnType = method.getReturnType();
        if (returnType.isPrimitive()) {
            if (returnType == boolean.class) return false;
            if (returnType == int.class) return 0;
            // 其他基本类型可按需补充
        }
        return null;
    }
}

3. 条件控制代理并纳入Spring上下文

核心是通过BeanPostProcessor替换Spring容器中的原Bean为代理对象,确保代理被Spring管理:

@Component
public class ProxySwitchProcessor implements BeanPostProcessor {
    // 可从配置文件读取,比如@Value("${proxy.mode:retain}")
    private final String proxyMode = "retain"; // 可选值:retain / placeholder

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 检查当前Bean是否实现了被@ProxyTargetInterface标注的接口
        Class<?>[] interfaces = bean.getClass().getInterfaces();
        for (Class<?> iface : interfaces) {
            if (iface.isAnnotationPresent(ProxyTargetInterface.class)) {
                // 根据模式创建对应代理
                if ("retain".equals(proxyMode)) {
                    return Proxy.newProxyInstance(
                            bean.getClass().getClassLoader(),
                            interfaces,
                            new RetainLogicHandler(bean)
                    );
                } else if ("placeholder".equals(proxyMode)) {
                    return Proxy.newProxyInstance(
                            bean.getClass().getClassLoader(),
                            interfaces,
                            new PlaceholderLogicHandler()
                    );
                }
            }
        }
        return bean;
    }
}

4. 验证代理生效

通过Spring注入代理对象测试效果:

@SpringBootTest
public class ProxyTest {
    @Autowired
    private UserService userService;

    @Test
    public void testProxyBehavior() {
        userService.doBusiness();
        // retain模式:输出代理增强日志 + 原业务逻辑
        // placeholder模式:无业务逻辑输出,仅返回默认值
    }
}

注意事项

  • 若目标类无接口,可替换为CGLIB代理(用Enhancer创建类代理)。
  • 代理模式可通过配置中心或环境变量动态控制,无需硬编码。
  • 之前手动创建代理未纳入Spring上下文,是因为未替换容器中原Bean实例,此方案通过BeanPostProcessor完成替换,确保代理对象被Spring管理。

内容的提问来源于stack exchange,提问作者Kaspersky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:33:32