前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >揭秘Spring框架:Spring条件装配的奥妙【Spring | Java】

揭秘Spring框架:Spring条件装配的奥妙【Spring | Java】

原创
作者头像
用户9055382
发布2024-12-22 17:02:10
发布2024-12-22 17:02:10
780
举报

⭐**简单说两句**⭐

**✨ 正在努力的小新~**

**💖 超级爱分享,分享各种有趣干货!**

**👩‍💻 提供:模拟面试 | 简历诊断 | 独家简历模板**

**🌈 感谢关注,关注了你就是我的超级粉丝啦!**

**🔒 以下内容仅对你可见~**

<font color='#20afdf'>**作者:**</font>**不正经小新**,**CSDN后端领域新星创作者 |阿里云专家博主**

<font color='#f00f6d'>**CSDN**个人主页</font>:不正经小新

🔎**GZH**:不正经小新

🎉<font color='#2979ff'>欢迎关注</font>🔎<font color='#ff69b4'>点赞</font>👍<font color='#ba2bec'>收藏</font>⭐️<font color='#fd700'>留言</font>📝


@toc

说在前面

本系列文章是Spring学习笔记,参考书 《SpringBoot源码解读与原理分析》

阅读的一个小要求:**至少会使用SpringBoot或Spring或者天才型选手**

本系列文章将会持续更新,更新速度取决于各位读者大大的<font color =#9642cd>点赞收藏和留言</font>

思维导图

为了方便读者了解文章整体内容,我给出了一张思维导图,希望有所帮助

🌱Spring条件装配

🌿条件装配简介

Spring框架是一个开源的Java平台,它提供了全面的基础设施支持,用于创建Java应用程序。在Spring框架中,条件装配(Conditional Wiring)是一种基于条件的配置技术,它允许开发者根据不同的条件来决定是否创建某个Bean或者使用某个配置类。


概念:

条件装配的核心思想是让Spring容器在运行时根据特定的条件来决定是否装配(创建和配置)某个Bean。这些条件可以是基于类的存在、环境属性、表达式的计算结果等。


作用:

1、环境特定的配置:在不同的环境(开发、测试、生产)中,可能需要不同的Bean配置。条件装配允许开发者为不同的环境定义特定的Bean,而不需要在代码中硬编码这些差异。

2、特性开关:通过条件装配,可以根据是否包含某个特性来决定是否装配相关的Bean。这在实现功能开关时非常有用,可以在不修改代码的情况下,通过配置来开启或关闭某些功能。

3、优化性能:如果某些Bean只在特定的条件下需要,那么在其他条件下不创建这些Bean可以节省资源,提高应用性能。

4、模块化:条件装配支持应用的模块化设计,不同的模块可以根据需要独立配置,而不会相互干扰。

5、简化配置:在大型应用中,条件装配可以帮助减少配置的复杂性,通过集中管理条件逻辑,而不是在多个地方重复相同的配置。

☘️基于Profile装配

🎍概念

在Spring3.1中,已经引入了Profile的概念,我们看下Spring源码中的描述:

@Profile可以以下列任何方式使用注解:

  • 作为直接或间接使用 注释的任何 @Component类的类型级注解,包括 @Configuration 类
  • 作为元注解,用于组合自定义原型注解
  • 作为任何 @Bean 方法的方法级注解

简单来说就是:Profile提供了一种“基于环境的配置”:根据当前项目的不同运行时环境,可以动态的注册与当前运行环境匹配的组件~

🎋@Profile实战

我们现在来实战一下Profile这个注解~

需求背景:调酒师只会在城市中工作,在荒郊野外的时候,调酒师不会进行工作。

分析:我们在代码层面就是在调酒师的配置类上加一个@Profile注解

BartenderConfiguration调酒师配置类 代码清单

代码语言:java
复制
@Configuration

@Profile("city")

public class BartenderConfiguration {



    @Bean

    public Bartender getBartender() {

        return new Bartender("调酒师-01");

    }



    @Bean

    public Bartender getBartender02() {

        return new Bartender("调酒师-02");

    }

}

为ApplicationContext设置Profile

代码语言:java
复制
    @Test

    public void testProfile() {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.getEnvironment().setActiveProfiles("city");

        context.register(BartenderConfiguration.class);

        context.refresh();

        String[] beanDefinitionNames = context.getBeanDefinitionNames();

        Stream.of(beanDefinitionNames).forEach(log::info);

    }

运行看结果

这段Java代码用于测试Spring框架中的配置文件激活功能。具体功能如下:

  • 创建一个AnnotationConfigApplicationContext实例。
  • 设置当前环境的活动配置文件为"city"。
  • 注册BartenderConfiguration配置类。
  • 刷新上下文,加载所有配置。
  • 获取所有Bean定义名称,并通过日志输出

【提示】:AnnotationConfigApplicationContext在创建对象时,如果直接传入了配置类,则会立即初始化IOC容器,在不传入配置类的情况下,内部不会执行初始化逻辑,而是要等到手动调用refresh方法才会初始化IOC容器,在初始化的过程中,会顺带将环境配置一起处理~

代码语言:mermaid
复制
flowchart TD

    A[创建上下文实例] --> B[设置活动配置文件为 city]

    B --> C[注册配置类 BartenderConfiguration]

    C --> D[刷新上下文]

    D --> E[获取所有 Bean 定义名称]

    E --> F[遍历并输出 Bean 名称]

可以一些读者已经发现问题所在了,在上面的代码中,我们的环境是在代码中显示指定的,如果哪天需要重新更换,还得改代码重新部署,就麻烦了~

其实啊,Spring框架早就给我们考虑了这种情况,所以还提供了一些其他的方式,比如命令行参数配置~

我们看下怎么配置,在Spring源码中可以找到这个,就是通过spring.profiles.active来传递的~

我们在代码中注释掉context.getEnvironment().setActiveProfiles("city");

然后再Idea中设置命令行启动参数~

点击运行后,同样发现还是打印了我们的调酒师~

Profile机制在SpringBoot中运用的也很经典,使用spring.profiles.active可以指定环境配置application.properties文件可以通过添加后缀来区分不同环境,比如 application-dev.properties、application-test.properties等等~

🍃@Profile的不足

虽然Profile很牛掰,但是也是有缺点的,比如:吧台中需要有老板或负责人,如果都没的话,那么吧台就不应该存在~,这个时候Profile就不太好实现了,因为Profile是控制的整个项目的运行环境,没办法根据单个Bean来决定是否装配 ~

那怎么解决这个问题呢?

Spring其实也给我们想到了,给我们提供了另一个注解:@Conditional

🍂基于Conditional的条件装配

🍁概念

@Conditional是在Spring4.0版本中推出的,他可以让Bean注册到IOC容器时,必须满足@Conditional上的条件~

🍄@Conditional实战使用

来,接着奏乐,接着舞,我们简单实现下上面的需求:吧台需要依赖老板的存在~

思路分析:

  • 编写判断Boss类是否存在的判断类
  • 在BarConfiguration上添加装配条件

我们先编写判断Boss类是否存在的判断类,怎么写呢,我们直接实现Condition的接口,然后看容器中是否存在Boss类就OK了~

ExistBossConditon代码清单

代码语言:java
复制
public class ExistBossConditon implements Condition {

    @Override

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        return context.getBeanFactory().containsBeanDefinition(Boss.class.getName());

    }

}

BarConfiguration代码清单

代码语言:java
复制
@Configuration

public class BarConfiguration {

    @Conditional(ExistBossConditon.class)

    @Bean

    public Bar bbar() {

        return new Bar();

    }

}

EnableTavern注解代码清单

代码语言:java
复制
@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Import({Boss.class, BartenderConfiguration.class})

public @interface EnableTavern {

}

TavernConfiguration代码清单

代码语言:java
复制
@Configuration

@EnableTavern

public class TavernConfiguration {

}

测试类代码清单

代码语言:java
复制
    @Test

    public void testConditional() {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.register(TavernConfiguration.class, BarConfiguration.class);

        context.refresh();

        String[] beanDefinitionNames = context.getBeanDefinitionNames();

        Stream.of(beanDefinitionNames).forEach(log::info);

    }

运行结果

🐚@ConditionOnXX系列注解

SpringBoot中对Conditional注解进行了一些扩展

比如:

  • @ConditionalOnBean:当容器中有指定Bean时进行实例化。
  • @ConditionalOnMissingBean:当容器里没有指定Bean时进行实例化。
  • @ConditionalOnClass:当classpath类路径下有指定类时进行实例化。
  • @ConditionalOnMissingClass:当类路径下没有指定类时进行实例化。
  • @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
  • @ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
  • @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
  • @ConditionalOnExpression:基于SpEL表达式的条件判断。
  • @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。

<font color='#f00f6d'>【都看到这了,点点赞点点关注呗,爱你们】</font>😚😚

💬

**✨ 正在努力的小新~**

**💖 超级爱分享,分享各种有趣干货!**

**👩‍💻 提供:模拟面试 | 简历诊断 | 独家简历模板**

**🌈 感谢关注,关注了你就是我的超级粉丝啦!**

**🔒 以下内容仅对你可见~**

<font color='#20afdf'>**作者:**</font>**不正经小新**,**CSDN后端领域新星创作者 |阿里云专家博主**

<font color='#f00f6d'>**CSDN**个人主页</font>:不正经小新

🔎**GZH**:不正经小新

🎉<font color='#2979ff'>欢迎关注</font>🔎<font color='#ff69b4'>点赞</font>👍<font color='#ba2bec'>收藏</font>⭐️<font color='#fd700'>留言</font>📝

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🌱Spring条件装配
    • 🌿条件装配简介
    • ☘️基于Profile装配
      • 🎍概念
      • 🎋@Profile实战
      • 🍃@Profile的不足
    • 🍂基于Conditional的条件装配
      • 🍁概念
      • 🍄@Conditional实战使用
      • 🐚@ConditionOnXX系列注解
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档