Spring 多实例注入

文章目录
  • [1. Spring 多实例注入的应用场景](#1. Spring 多实例注入的应用场景)
  • [2. Spring 多实例注入的使用](#2. Spring 多实例注入的使用)
      • [2.1 通过 ApplicationContext 获取多实例](#2.1 通过 ApplicationContext 获取多实例)
      • [2.2 配置 @Scope 的 proxyMode 属性获取多实例](#2.2 配置 @Scope 的 proxyMode 属性获取多实例)

1. Spring 多实例注入的应用场景

Spring 容器中保存的 bean 默认是单例的,通常来说这样做可以降低 bean 对象创建的频率,在某些访问量大的场景下可以节省对象创建消耗的时间,提高响应性能。但在一些其他场景,比如脚本调度处理多个消息队列中的消息,这时候拉取各个队列消息的步骤是完全相同的,只不过各条队列的名称和密码不一样,显然可以使用一个专门的 processor来处理,以便减少重复代码。这样一来,一个解决方式是每一条队列使用一个单独的processor实例,这就需要用到 Spring 的多实例注入了

2. Spring 多实例注入的使用

Spring 框架中, 可以通过在一个Java 类上添加注解 @Scope 并配置注解相关属性将该类声明为 原型作用域,这样每次从 Spring 容器中获取其实例的时候都会返回一个新的对象

2.1 通过 ApplicationContext 获取多实例

如果在一个Java 类上只添加注解 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE),这种声明为多实例的 bean 对象通过注解 @Resource@Autowired 自动注入无法保证每次获取的都是新的实例,一个解决方法是通过 Spring 的 ApplicationContext,直接获取容器中的 bean 实例,示例代码如下

  1. 首先在目标类上添加注解@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)声明其每次使用都需要新的实例

    复制代码
    @Component
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public class MessageProcessor {
       ......
       private String queueName;
       private String passWord;
       ......
    }
  2. 创建实现ApplicationContextAware 接口的 SpringBeanProvider 工具类。使用时注入 SpringBeanProvider 实例,调用其 getBean()方法,传入指定参数即可获取到类的新实例

    复制代码
    @Component
    public class SpringBeanProvider implements ApplicationContextAware {
    
     private ApplicationContext applicationContext;
    
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
    
     }
    
     /**
      * 通过 beanName 获取 Bean
      * @param beanName
      * @return
      */
     public Object getBean(String beanName) {
         return applicationContext.getBean(beanName);
     }
    
     /**
      * 通过class获取Bean
      * @param clazz
      * @param <T>
      * @return
      */
     public <T> T getBean(Class<T> clazz) {
         return applicationContext.getBean(clazz);
     }
    
     /**
      * 通过 beanName ,以及Clazz返回指定的Bean
      * @param beanName
      * @param clazz
      * @param <T>
      * @return
      */
     public <T> T getBean(String beanName, Class<T> clazz) {
         return applicationContext.getBean(beanName, clazz);
     }
    }
2.2 配置 @Scope 的 proxyMode 属性获取多实例

这种方式需要在实现类上添加注解@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)指定类的代理模式,这样使用注解 @Resource@Autowired 自动注入也能保证每次方法调用都是基于新对象,其底层实现原理是基于 AOP 机制

  1. 使用 ScopedProxyFactoryBean 作为代理类替换掉目标类,生成相应的 BeanDefintion 注册到容器中
  2. 上层应用获取目标类实例时,实际最终获取到代理类 ScopedProxyFactoryBean 实例
  3. ScopedProxyFactoryBean 作为目标实例代理对象,其每次方法调用时会触发拦截器执行,在拦截器逻辑中会通过 BeanFactory#getBean() 方法新建目标对象,从而实现多例
复制代码
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MessageProcessor {
   ......
   private String queueName;
   private String passWord;
   ......
}
相关推荐
01二进制代码漫游日记几秒前
C++基础入门速通
java·开发语言·c++
Herbert_hwt2 分钟前
第六章 Java深入理解接口、函数式接口与lambda表达式
java·开发语言·算法
AINative软件工程17 分钟前
AI Agent 证据仲裁工程实践:别让检索结果按自信程度撒谎
人工智能·后端·ai编程
API快乐传递者18 分钟前
电商竞品分析接口实战指南:从数据采集到决策洞察的全链路方案
java·python
卷无止境24 分钟前
FastAPI 权限管理实战:从 ACL 到 RBAC 的那些门道
后端·python·fastapi
程序员黑豆8 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
GreenTea9 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
风流 少年9 小时前
Spring AI 2.0:Memory
java·后端·spring
码匠许师傅9 小时前
【C++ 面试真题】聊聊 C++ 的移动语义与右值引用
java·c++·面试
万少9 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端