Spring Boot 系统学习第五天:Spring循环依赖实战经验 备份

1 概述

        本篇主要介绍使用依赖注入的一些实战经验。

2 把握Bean的作用域

        前面说到Setter方法注入时,提到了Spring中的Bean作用域的概念。作用域描述了Bean在Spring IoC容器上下文中的生命周期和可见性。现在讨论Spring框架中不同类型的Bean作用域及其在使用上的指导规则。

        如果想要通过注解来设置Bean的作用域,可以使用下面示例代码:

@Configuration
public class Appcofig {
    @Bean
    @Scope("singleton")
    public HealthRecordService createHealthRecordService(){
        return new HealthRecordServiceImpl();
    }
}
public interface HealthRecordService {
}
public class HealthRecordServiceImpl implements HealthRecordService{
}

        可以看到这里使用了一个@Scope注解来指定Bean的作用域为单例的singleton。在Spring中,除了单例作用域之外,还有一个prototype,即原型作用域,也可成为多例作用域,与单例作用域进行区分。使用方式上,同样可以使用下列代码进行设置。

@Configuration
public class Appcofig1 {
    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public HealthRecordService createHealthRecordService(){
        return new HealthRecordServiceImpl();
    }
}

        在SpringIoC容器中,Bean的默认作用域是单例,也就是不管有多少个对Bean的引用,容器只会创建一个实例。而原型作用域则不同,每次请求Bean时,Spring IoC容器都会创建一个新的对象实例。

        从两种作用域的效果而言,总结出一条开发上的经验,即对于有状态的Bean,应该使用原型作用域,反之则使用单例作用域。

        那么,什么样的Bean是有状态的呢?结合Web应用程序,可以明确对于每次HTTP请求而言,都应该创建一个Bean来代表这一次的请求对象。同样,对于会话而言,也需要针对每个会话创建一个会话状态对象。这些都是创建的有状态的Bean。为了更好地管理这些Bean的生命周期,Spring还专门针对Web开发场景提供了对应的request和session作用域。

3 灵活使用注解配置

        在使用Spring依赖注入类型时,通常可以使用XML配置、Java代码配置以及注解配置这三种方式。随着Spring Boot框架的流程,使用注解配置已经成为目前最主流的开发方法。除了前面已经给出的最常见的@Autowired注解,Spring Boot框架还提供了一组非常有用的注解帮助我们更好的管理所注入的对象,包括@Primary注解和@Qualifier注解。

        在Spring IoC容器中,针对HealthRecordService这样一种接口类型,原则上容器只允许注入一个实现类。如果存在该类型的多个对象实例,那么容器就会NoUniqueBeanDefinitionException,意味着容器无法决定选择哪一个实例来进行注入。这时候就可以使用@Primary注解来帮助容器做出选择,该注解的使用方式如下:

@Component
public class HealthRecordServiceImplA implements HealthRecordService{
}
@Component
@Primary
public class HealthRecordServiceImplB implements HealthRecordService{
}

        这时候,Spring IoC容器只会注入HealthRecordServiceImplB这个实例类,这在管理针对某种类型的多个实例时非常有效。

        和@Primary注解的应用场景类似,@Qualifier注解为我们选择实例类进行注入提供了更加灵活的实现方式,代码如下:

@Component
@Qualifier("healthRecordServiceImplA")
public class HealthRecordServiceImplA implements HealthRecordService{
}
@Component
@Qualifier("healthRecordServiceImplB")
public class HealthRecordServiceImplB implements HealthRecordService{
}

        可以看到,这里对不同的实现类,通过@Qualifier注解设置了不同的名称,这样在使用时就可以通过该名称获取不同的实例,代码如下:

public class HealthRecordServiceImplA implements HealthRecordService{
    @Autowired
    @Qualifier("healthRecotdServiceA")
    private HealthRecordService healthRecordService;
}

4 设置组件扫描范围

        在Spring中,可以通过设置组件扫描范围来简化Bean的注入配置。因为任何类都位于某一个包接口之下,所以Spring提供了一个@ComponentScan注解,该注解在需要大规模对象注入的场景下非常有用,代码如下:

@Configuration
@ComponentScan(basePackages = "com.jay")
public class Appcofig2 {
}

        在这个示例中,Spring会扫描由basePackages指定的包路径com.jay及其子路径下的所有Bean,并把它们注入到容器中,当前,首先需要再这些类上添加@Component注解以及由该注解衍生的@Service、@Pepository、@Controler等注解。

5 不同配置的性能分析

        首先要讨论的是前面介绍的@ComponentScan注解。因为该注解会扫描basePackages指定的包中的所有组件,所以如果指定包中的组件并不需要在应用程序启动时就全部加载到容器中。那么对包路径进行精细化设计是一个实践技巧。例如,可以通过设置一个列表来细化具体的包结构路径。代码如下:

@Configuration
@ComponentScan(basePackages = "com.jay.controller","com.jay.service")
public class Appcofig2 {
}

        然后要讨论的是单例模式和原型模式对性能的影响。在Spring中,当把Bean范围设置为prototype,每次请求Bean时,Spring IoC容器都会创建一个新的对象实例。所以,使用原型模式在创建过程中会对性能产生影响,对那些初始化过程需要消耗巨大资源的对象而言尤其如此,这些对象常见的有网络连接对象、数据库连接对象等。因此,对这些对象,应该避免使用原型模式。或者,应该在使用前仔细设计并对性能进行充分测试。

        最后一个值得讨论的性能分析点在于Spring IoC容器的延迟加载(Lazy Loading)和预加载(Preloading)机制。通过@Autowired注入的Bean都是在Spring IoC容器启动时被创建和初始化的,这个过程被称为预加载。但有时候,希望能够延迟Bean的加载时机,这时候就可以使用@Lay注解,示例如下:

@Component
@Lazy
public class HealthRecordServiceImpl implements HealthRecordService{
}

        添加了@Lazy注解的效果是只有在使用到这个Bean时它才会去初始化,而不是在Spring IoC容器启动时直接初始化,这样就可以节省容器资源。

        延迟加载确保在请求时动态加载Bean,预加载确保在使用Bean之前加载Bean。Spring IoC容器默认使用预加载。然后,在容器启动时就加载所有类并不是一个明智的决定,因为有些Bean实例会非常消耗资源。应该根据实际情况选择具体的加载方法。

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

geminigoth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值