文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

绝对让你大开眼界的Spring依赖注入问题

2024-11-29 19:28

关注

1. 简介

本篇文章旨在深入探讨将原型(Prototype)作用域的bean注入到单例(Singleton)作用域bean中的多种策略,并详细剖析每种方法的优缺点。在Spring框架中,默认情况下bean是单例的,这意味着它们在应用的生命周期内仅被创建一次并共享。然而,当需要将原型bean(每次请求都创建一个新实例)注入到单例bean中时,就会出现作用域注入问题。如下示例:

@Configuration
public class AppConfig {
  @Bean
  @Scope(BeanDefinition.SCOPE_PROTOTYPE)
  public PrototypeBean prototypeBean() {
    return new PrototypeBean() ;
  }
  @Bean
  public SingletonBean singletonBean() {
    return new SingletonBean() ;
  }
}

在该配置类中,将PrototypeBean定义为原型bean,SingletonBean定义为单例,该单例bean的定义如下:

@Component
public class SingletonBean {


  @Resource
  private PrototypeBean prototypeBean ;  
  public void test() {
    System.out.println(this.prototypeBean) ;
  }
}

在这通过@Resource注解,注入原型bean。接下来我们通过如下的代码进行测试:

ConfigurableApplicationContext context = SpringApplication.run(App.class, args) ;
SingletonBean bean = context.getBean(SingletonBean.class) ;
bean.test() ;
bean.test() ;
bean.test() ;

以上调用三次test方法,我们期望的是每次调用打印的prototypeBean属性都不是同一个,结果如下:

com.pack.PrototypeBean@69fb6037
com.pack.PrototypeBean@69fb6037
com.pack.PrototypeBean@69fb6037

三次打印都是同一个。这种不同作用域的注入该如何解决呢?接下来我将介绍8种方式解决。

2. 解决办法

2.1 单例bean实现ApplicationContextAware

public class SingletonBean implements ApplicationContextAware {
  private ApplicationContext context;
  public void test() {
    System.out.println(this.context.getBean(PrototypeBean.class)) ;
  }
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.context = applicationContext ;
  }
}

每调用test方法时都会通过ApplicationContext对象从容器中获取新实例。

缺点:

除了这2缺点,用起来感觉还行啊

2.2 通过jakarta的Provider注入

public class SingletonBean {
  @Resource
  private jakarta.inject.Provider provider ;
  public void test() {
    System.out.println(provider.get()) ;
  }
}

这里通过jakarta.inject包中的Provider接口注入原型bean。每次调用get方法都会从容器中再次获取一个新的实例对象。

2.3 借助Spring提供的ObjectProvider接口

public class SingletonBean {
  @Resource
  private ObjectProvider objectProvider ;
  public void test() {
    System.out.println(objectProvider.getIfAvailable()) ;
  }
}

直接注入ObjectProvider接口对象,该接口提供了丰富的方法,不仅仅可以获取单个对象,也可以获取多个对象(集合),包括如下可用方法:

图片

2.4 借助Spring的ObjectFactory接口

public class SingletonBean {
  @Resource
  private ObjectFactory objectFactory ;
  public void test() {
    System.out.println(objectFactory.getObject()) ;
  }
}

该接口与上面ObjectProvider接口挺像,但是ObjectFactory是函数式接口只有一个getObject方法,并且只能返回一个对象。

2.5 使用@Lookup注解

public class SingletonBean {
  
  public void test() {
    System.out.println(get()) ;
  }
  @Lookup
  protected PrototypeBean get() {
    return null ;
  }
}

Spring 会将SingletonBean创建为代理对象并覆盖使用 @Lookup 注解的 get() 方法。每当我们调用get() 方法时,它会返回一个新的 PrototypeBean 实例。

2.6 注册Function类型的Bean

@Bean
public  Function, T> targetBean(ApplicationContext context) {
  return t -> context.getBean(t) ;
}

这里注册了Function类型的bean对象,而具体会是什么类型完全由使用的地方决定。

public class SingletonBean {
  @Resource
  private Function, PrototypeBean> targetBean ;
  public void test() {
    System.out.println(targetBean.apply(PrototypeBean.class)) ;
  }
}

通过定义Function类型的bean,这里我们就可以不限制具体是那个类型的原型bean,这就非常的通用了。

2.7 作用域代理

@Component
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean {
}

在@Scope注解上配置proxyMode=TARGET_CLASS这样配置以后,容器将会为PrototypeBean创建代理对象。也是能够保证每次获取的都是新的实例对象。

2.8 使用@Lazy注解

public class SingletonBean {
  @Resource
  @Lazy
  private PrototypeBean prototypeBean ;
}

通过@Lazy注解后,这里注入的PrototypeBean将会是一个代理对象,这样也可以保证每次使用时都是新的实例对象。

来源:Spring全家桶实战案例源码内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯