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

能否在每次@Autowire注入(构造器、变量、方法)前执行代码?

解决Spring自动装配前动态添加@Primary代理的问题

首先明确:postProcessBeforeInitialization时机太晚——Spring的Bean生命周期是「实例化 → 依赖注入 → 初始化(执行postProcessBeforeInitialization)」,注入发生在初始化之前,所以这个阶段才加代理,早已经过了依赖注入的环节,自然会因为没有@Primary导致注入失败。

针对你的需求,提供两种高效避开全量扫描的解决方案:

方案一:基于BeanFactoryPostProcessor提前注册代理BeanDefinition

不用自己全量扫描组件,而是利用Spring已经完成组件扫描后注册的BeanDefinition,只筛选你需要处理的接口(比如标记自定义注解的接口),动态生成@Primary的代理BeanDefinition,注册到容器中。这个时机早于依赖注入,能保证注入时存在首选Bean。

代码示例

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

// 处理器:筛选目标接口,注册@Primary代理
@Component
public class DynamicProxyRegistrar implements BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Set<Class<?>> targetInterfaces = collectTargetInterfaces(beanFactory);
        for (Class<?> targetInterface : targetInterfaces) {
            String[] implBeanNames = beanFactory.getBeanNamesForType(targetInterface);
            if (implBeanNames.length > 1) {
                // 创建代理Bean的定义
                GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition();
                proxyBeanDef.setBeanClass(ProxyFactoryBean.class);
                proxyBeanDef.getPropertyValues().add("proxyInterfaces", targetInterface);
                // 设置动态选择实现的InvocationHandler
                proxyBeanDef.getPropertyValues().add("invocationHandler", 
                    new DynamicServiceHandler(targetInterface, beanFactory));
                // 标记为@Primary,成为注入首选
                proxyBeanDef.setPrimary(true);
                
                // 注册代理Bean到容器
                String proxyBeanName = targetInterface.getSimpleName() + "DynamicProxy";
                ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(proxyBeanName, proxyBeanDef);
            }
        }
    }

    // 筛选标记了自定义注解的接口,避免全量扫描
    private Set<Class<?>> collectTargetInterfaces(ConfigurableListableBeanFactory beanFactory) {
        Set<Class<?>> interfaces = new HashSet<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            try {
                Class<?> beanClass = Class.forName(beanDef.getBeanClassName());
                for (Class<?> iface : beanClass.getInterfaces()) {
                    if (iface.isAnnotationPresent(DynamicProxyTarget.class)) {
                        interfaces.add(iface);
                    }
                }
            } catch (ClassNotFoundException e) {
                // 忽略无法加载的类,不影响核心逻辑
            }
        }
        return interfaces;
    }

    // 动态选择实现的InvocationHandler
    static class DynamicServiceHandler implements InvocationHandler {
        private final Class<?> targetInterface;
        private final ConfigurableListableBeanFactory beanFactory;

        public DynamicServiceHandler(Class<?> targetInterface, ConfigurableListableBeanFactory beanFactory) {
            this.targetInterface = targetInterface;
            this.beanFactory = beanFactory;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 这里根据实际场景逻辑选择具体实现,比如从ThreadLocal获取场景标识
            String currentScenario = getCurrentScenario();
            // 假设实现类命名规则是「场景名+接口名」,比如BusinessUserService、RestUserService
            String targetBeanName = currentScenario + targetInterface.getSimpleName();
            Object targetBean = beanFactory.getBean(targetBeanName);
            return method.invoke(targetBean, args);
        }

        private String getCurrentScenario() {
            // 实际业务中替换为场景获取逻辑
            return "Business";
        }
    }
}

优势

  • 利用Spring已有的BeanDefinition数据,不用自己全量扫描,性能更高;
  • 代理BeanDefinition在依赖注入前就已注册,注入时能直接找到@Primary的代理,避免注入失败。

方案二:自定义AutowireCandidateResolver动态生成代理

直接在依赖注入的候选解析阶段,动态生成代理并作为首选Bean返回,完全不需要提前注册BeanDefinition,彻底避开组件扫描的开销。

代码示例

// 自定义候选解析器:注入时动态生成代理
@Component
public class DynamicAutowireResolver extends SimpleAutowireCandidateResolver {

    private final ConfigurableListableBeanFactory beanFactory;

    public DynamicAutowireResolver(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
        Class<?> requiredType = descriptor.getDependencyType();
        // 只处理接口类型且存在多个实现的情况
        if (requiredType.isInterface() && candidates.size() > 1) {
            // 动态生成JDK代理
            return Proxy.newProxyInstance(
                    requiredType.getClassLoader(),
                    new Class[]{requiredType},
                    new DynamicServiceHandler(requiredType, beanFactory)
            );
        }
        // 其他情况沿用Spring默认逻辑
        return super.determineAutowireCandidate(candidates, descriptor);
    }

    // 同方案一的InvocationHandler实现
    static class DynamicServiceHandler implements InvocationHandler {
        private final Class<?> targetInterface;
        private final ConfigurableListableBeanFactory beanFactory;

        public DynamicServiceHandler(Class<?> targetInterface, ConfigurableListableBeanFactory beanFactory) {
            this.targetInterface = targetInterface;
            this.beanFactory = beanFactory;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String currentScenario = getCurrentScenario();
            String targetBeanName = currentScenario + targetInterface.getSimpleName();
            Object targetBean = beanFactory.getBean(targetBeanName);
            return method.invoke(targetBean, args);
        }

        private String getCurrentScenario() {
            return "Business";
        }
    }
}

// 配置类:将自定义解析器设置到Autowired注解处理器
@Component
public class ResolverConfigurer implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        AutowiredAnnotationBeanPostProcessor autowiredProcessor = 
            beanFactory.getBean(AutowiredAnnotationBeanPostProcessor.class);
        autowiredProcessor.setAutowireCandidateResolver(new DynamicAutowireResolver(beanFactory));
    }
}

优势

  • 完全不需要提前注册任何BeanDefinition,仅在注入时动态处理,性能最优;
  • 逻辑更灵活,可针对每次注入的上下文动态调整代理行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:35:34