Spring很常用的@Conditional注解的使用场景和源码解析

Spring中@Conditional注解的使用场景和源码解析

1. 使用场景

通俗的说,@Conditional是一个条件注解,允许我们根据特定条件来控制是否创建一个Bean。因此, @Conditional这个注解的核心就是用来控制 Bean 的创建的。

在实际开发中,我们经常会碰到类似这样的场景:我们需要根据不同的条件来决定是否创建某一个 Bean。比如,我们需要根据当前所处的环境(如开发、测试、生产)来控制 Bean 的创建。在这种场景下,就可以使用@Conditional注解。

例如,我们可以根据当前的操作系统来控制创建 Bean:

@Configuration
public class AppConfig {

    @Bean("osService")
    @Conditional(ConditionalOnWindows.class)
    public OsService windowsService() {
        return new WindowsService();
    }

    @Bean("osService")
    @Conditional(ConditionalOnLinux.class)
    public OsService linuxService() {
        return new LinuxService();
    }
}

public class ConditionalOnWindows implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String os = context.getEnvironment().getProperty("os.name");
        return os.toLowerCase().contains("windows");
    }
}

public class ConditionalOnLinux implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String os = context.getEnvironment().getProperty("os.name");
        return os.toLowerCase().contains("linux");
    }
}

在上面的代码中,我们定义了两个方法,一个是windowsService,一个是linuxService,这两个方法都使用了@Conditional注解,并且分别传入了不同的匹配条件。当我们启动程序时,Spring会通过matches方法来判断操作系统是不是Windows或Linux,从而决定创建哪个Bean。

除了可以用来控制 Bean 的创建外,@Conditional还可以用来控制@Configuration配置类的加载,达到在不同的条件下只加载特定类的目的。

2. 源码解析

@Conditional本质上是一个注解工厂,它会根据我们传入的匹配条件来实例化一个Condition实例,从而控制Bean的创建。

例如,我们举个例子,用一个小小的Java程序来演示:

public class SpringConditionalDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();
        OsService osService = (OsService) context.getBean("osService");
        System.out.println(osService.getOsName());
    }
}

这个程序创建了一个Spring上下文,并加载了AppConfig。在AppConfig中,我们定义了两个Bean,使用了@Conditional注解,并传入了特定的匹配条件。

我们可以通过打断点来跟踪看看Spring都做了什么:

  1. 首先,AnnotationConfigApplicationContext加载了我们的AppConfig。

  2. 然后,AnnotationConfigApplicationContext进行了refresh操作。

  3. 在refresh过程中,AnnotationConfigApplicationContext调用了finalizeBeanFactory()方法。

  4. 在这个方法中,AnnotationConfigApplicationContext会遍历到我们的@Bean注解,在遍历到@Bean注解时,Spring发现了我们的@Bean使用了@Conditional注解,并且传入了我们定义的匹配条件。

  5. 在这个时候,Spring会根据我们传入的匹配条件,实例化一个Condition实例,也就是我们的ConditionalOnWindows或ConditionalOnLinux实例。

  6. 这个Condition实例有一个matches方法,Spring就会通过这个matches方法来判断我们的条件是否匹配。

  7. 如果条件匹配,那么就会创建Bean,否则就会跳过这个Bean的创建。

从上面的过程可以看出,@Conditional注解的关键在于Condition实例的实例化和matches方法的调用。

与此类似的,@Profile注解也是一个条件注解,其作用在于根据特定的Profile是否被激活,来控制Bean的创建。其原理和@Conditional相似,也是通过实例化一个ProfileCondition实例,然后调用matches()方法来判断特定的Profile是否被激活。

总结

@Conditional注解是一个非常有用的注解,可以根据特定的条件来控制Bean的创建。在实际开发中,我们可以根据需要自定义匹配条件,比如,根据操作系统、根据系统环境、根据特定的JVM参数等等来控制Bean的创建。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring很常用的@Conditional注解的使用场景和源码解析 - Python技术站

(0)
上一篇 2023年6月1日
下一篇 2023年6月1日

相关文章

  • SpringBoot使用JWT实现登录验证的方法示例

    以下是“SpringBoot使用JWT实现登录验证的方法示例”的完整攻略: 1. 什么是JWT? JWT(JSON Web Token)是由JSON生成的令牌,通常用于身份验证和授权。它是一个开放标准(RFC 7519),通过在不同方之间安全地传输声明来作为JSON Web签名(JWS)或JSON Web加密(JWE)的方式。在Spring Boot中使用J…

    Java 2023年5月20日
    00
  • Java Apache Commons报错“ZipUnsupportedEncryptionMethodException”的原因与解决方法

    “ZipUnsupportedEncryptionMethodException”是Java的Apache Commons类库中的一个异常,通常由以下原因之一引起: 压缩加密方法不支持:如果压缩加密方法不支持,则可能会出现此异常。例如,可能会尝试使用不支持的压缩加密方法或压缩文件使用不支持的压缩加密方法。 以下是两个实例: 例1 如果压缩加密方法不支持,则可…

    Java 2023年5月5日
    00
  • FCKeditor JSP版漏洞

    FCKeditor JSP版漏洞(CVE-2009-2265)是一种常见的跨站脚本攻击(XSS)漏洞,攻击者可以在网站页面上注入恶意脚本,从而窃取用户的敏感信息或者控制用户的会话。以下是详细讲解这个漏洞的完整攻略: 漏洞背景 FCKeditor是一个开源的富文本编辑器,其中包含了JSP版,但JSP版在处理文件上传方面存在漏洞。攻击者可以通过构造一个包含特制的…

    Java 2023年6月15日
    00
  • 高命中率的varnish缓存配置分享

    下面我来为你详细讲解“高命中率的varnish缓存配置分享”的完整攻略。 一、背景介绍 Varnish是一款高性能的HTTP反向代理服务器,它可以加速站点的访问速度,并为站点提供缓存服务。在使用Varnish时,我们需要合理配置缓存策略来提高缓存命中率和性能。 二、缓存策略配置 1. 确定缓存内容 首先,我们需要确定哪些内容需要缓存。可以根据站点的特点和访问…

    Java 2023年6月16日
    00
  • SpringBoot项目将mybatis升级为mybatis-plus的方法

    下面是详细讲解 SpringBoot 项目将 Mybatis 升级为 Mybatis-Plus 的方法: 一、前置准备 1. 项目环境 SpringBoot版本:2.5.1 Mybatis版本:3.5.4 2. 引入依赖 在项目 pom.xml 中的 dependencies 中,加入以下依赖: <!– Mybatis-plus –> &lt…

    Java 2023年5月20日
    00
  • 启用springboot security后登录web页面需要用户名和密码的解决方法

    下面是启用Spring Boot Security后登录Web页面需要用户名和密码的解决方法的完整攻略,包括以下步骤: 1. 添加Spring Boot Security依赖 在pom.xml文件中添加Spring Boot Security依赖: <dependency> <groupId>org.springframework.b…

    Java 2023年6月3日
    00
  • Redis分布式锁这样用,有坑?

    背景 在微服务项目中,大家都会去使用到分布式锁,一般也是使用Redis去实现,使用RedisTemplate、Redisson、RedisLockRegistry都行,公司的项目中,使用的是Redisson,一般你会怎么用?看看下面的代码,是不是就是你的写法 String lockKey = “forlan_lock_” + serviceId; RLock…

    Java 2023年4月17日
    00
  • java实现肯德基收银系统

    Java实现肯德基收银系统攻略 肯德基是一个全球知名的快餐品牌,设计和实现它的收银系统需要考虑到多种因素,例如订单管理、菜品管理、价格计算、支付方式、交易记录等。本文将介绍如何使用Java语言来设计和实现肯德基收银系统,包括以下步骤: 确定系统需求 首先需要明确肯德基收银系统需要实现的功能,包括: 菜品列表:系统需要维护肯德基提供的所有菜品的名称、价格和编号…

    Java 2023年5月30日
    00
合作推广
合作推广
分享本页
返回顶部