能否在每次@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
相关产品推荐
相关产品推荐

