当前位置: 首页 > news >正文

【SpringBoot】⭐️AutoConfiguration配置的前世今生

请添加图片描述


  1. 在 Spring Boot 之前(即传统的 Spring Framework 时代),配置主要依靠 XML 文件和Java 配置类,没有像 Spring Boot 那样的自动配置机制。
  2. SpringBoot有默认扫描主类所在包,传统 Spring Framework需要xml声明位置
  3. SpringBoot有内嵌服务器tomcat + 零配置启动,而传统 Spring Framework需外部 Tomcat 部署 + web.xml 配置
  4. SpringBoot有内置的 @ConditionalOnXxx 注解进行 条件化配置,而传统 Spring Framework需要手动实现 Condition 接口
  5. SpringBoot 属性配置直接yml配置,而Spring Framwork只有Properties 文件 + ${} 占位符
  6. SpringBoot 有自动配置机制: META-INF/spring.factories 自动发现,老版本没有
  7. SpringBoot 有常见默认的自动配置,而Spring Framework 需手动配置数据源、事务、MVC 等
  8. SpringBoot 的自动配置对于顺序是有强要求的(@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder ),而传统spring 是封装使用AnnotationConfigApplicationContext 来决定配置的执行顺序,不声明,就默认
  9. @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder这三个注解只能作用于自动配置类,而不能是自定义的@Configuration配置类。
  10. @Configuration类中,@Bean方法调用会使用CGLIB代理来拦截,确保返回的是同一个单例实例(每次调用被@Bean标记的方法,Spring会检查容器中是否已有该bean,有则返回容器中的,不会重新创建),而在普通的@Component类中,@Bean方法不会被代理,因此每次调用方法都会创建一个新的实例(除非在方法内部自己实现单例)。

历史

spring Framework时代 XMl

<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="..."><!-- 组件扫描 --><context:component-scan base-package="com.example"/><!-- 数据源配置 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/db"/><property name="username" value="root"/><property name="password" value="123456"/></bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven/><!-- MVC 配置 --><mvc:annotation-driven/><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean>
</beans>

spring 3.0

@Configuration
@EnableWebMvc
@ComponentScan("com.example")
@EnableTransactionManagement
public class AppConfig {@Beanpublic DataSource dataSource() {BasicDataSource ds = new BasicDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql://localhost:3306/db");ds.setUsername("root");ds.setPassword("123456");return ds;}@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}
}

@Enable 模块驱动(spring 3.1)

// 自定义注解开启模块
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyModuleConfig.class) // 导入配置类
public @interface EnableMyModule {}

条件化配置(Spring 4.0+)

@Configuration
public class MyAutoConfig {@Bean@ConditionalOnClass(DataSource.class) // 类路径存在时生效public DataSource dataSource() {// ...}@Bean@ConditionalOnMissingBean // 容器不存在该Bean时生效public MyService myService() {return new DefaultMyService();}
}

自动配置类

@Configuration
@Conditional(OnClassCondition.class)
public class DataSourceAutoConfig {@Bean@ConditionalOnMissingBeanpublic DataSource dataSource(Environment env) {// 从环境变量读取配置DataSource ds = new BasicDataSource();ds.setUrl(env.getProperty("spring.datasource.url"));// ...return ds;}
}








配置类的相关问题

@SpringBootApplication 默认是有包扫描的 ,内部是被 @ComponentScan标记的, 但如果配置类不在其默认的子包下,需要在启动类使用@ComponentScan(basePackages = {"com.csair", "其他包路径"}) 更改位置进行扫包

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}





当配置类 已经加上@Configuration注解 是不需要加上@Component注解的,因为@Configuration注解有标注@Component

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}





当然,如果你是使用简单的配置类,只需要添加@Configuration 就行了,但如果你想对其配置属性配置,就需要加上@EnableConfigurationProperties ,从底下代码可以看出 关系链: 配置类 需要属性注入,所以需要关联 属性类,而属性类的属性,又可以从阿波罗注入,这样也会安全一点

注解作用示例
@EnableConfigurationProperties激活 @ConfigurationProperties 类@EnableConfigurationProperties(DataSourceProps.class)
@ConfigurationProperties绑定配置文件到类(通常用在属性类上)@ConfigurationProperties(prefix=“app.datasource”)
@PropertySource加载自定义 properties 文件@PropertySource(“classpath:custom.properties”)

第一种写法

注意: 如果你已经在RocketMqMessageProperties类上 使用了@EnableConfigurationProperties, 同时又使用了@Component,这就会导致同一个类会被注册两次(两个Bean定义),因为@EnableConfigurationProperties 会将类交给Bean管理,所以去掉多余的@Component注解

@EnableConfigurationProperties(RocketmqMessageProperties.class)
@Configuration
public class RocketMqMessageConfig {private static final Logger logger = LoggerFactory.getLogger(RocketMqMessageConfig.class);@Value("${ly.rocketmq.serverAddr}")private String serverAddr;@Beanpublic RocketMQProducer newMessageMq(RocketMqMessageProperties rocketMqMessageProperties) {try {RocketMQProducerConfig rocketMQProducerConfig = RocketMQProducerConfig.newBuilder().serverAddr(serverAddr).appName(rocketMqMessageProperties.getProduceAppName()).topic(rocketMqMessageProperties.getProduceTopicName()).build();return MQProducerFactory.newBuilder().rocketMQProducerConfig(rocketMQProducerConfig).mqProducerType("CANDIDATE").build().createMQProducer();} catch (Exception e) {logger.error("消息池MQ配置初始化失败",e);}return null;}
}

第二种写法

注意

  1. 是需要将RocketMMessageProperties 属性类显示注册成@Bean才行,因为@ConfigurationProperties 是不会注册成Bean对象的 ,所以需要添加@Component 注解或其他,将其注册成Bean
  2. 如果有多个RocketMMessageProperties 属性类的Bean对象,需要@Autowired注入时加上注解@Qualifier指定其特殊的Bean
@Configuration
public class RocketMqMessageConfig {@Autowired RocketMqMessageProperties rocketMqMessageProperties;private static final Logger logger = LoggerFactory.getLogger(RocketMqMessageConfig.class);@Value("${ly.rocketmq.serverAddr}")private String serverAddr;@Beanpublic RocketMQProducer newMessageMq() {try {RocketMQProducerConfig rocketMQProducerConfig = RocketMQProducerConfig.newBuilder().serverAddr(serverAddr).appName(rocketMqMessageProperties.getProduceAppName()).topic(rocketMqMessageProperties.getProduceTopicName()).build();return MQProducerFactory.newBuilder().rocketMQProducerConfig(rocketMQProducerConfig).mqProducerType("CANDIDATE").build().createMQProducer();} catch (Exception e) {logger.error("消息池MQ配置初始化失败",e);}return null;}
}
@ConfigurationProperties(prefix = "mq.jd.message.sync.rocket", ignoreUnknownFields = false)
public class RocketMqMessageProperties implements Serializable {private static final long serialVersionUID = 6885212498401171664L;private String configUrl;private String produceAppName;private String produceTopicName;public String getConfigUrl() {return configUrl;}public void setConfigUrl(String configUrl) {this.configUrl = configUrl;}public String getProduceAppName() {return produceAppName;}public void setProduceAppName(String produceAppName) {this.produceAppName = produceAppName;}public String getProduceTopicName() {return produceTopicName;}public void setProduceTopicName(String produceTopicName) {this.produceTopicName = produceTopicName;}
}
app:id: shqxe
apollo:meta: http://127.0.0.1:8081bootstrap:enabled: trueeagerLoad:enabled: truenamespaces: config.yaml,spring-config.yaml,switch.yamlspring:cloud:config:import-check:enabled: false




当然,你也可添加 条件化注解 ,@ConditionalOnClass, @ConditionalOnProperty, @ConditionalOnMissingBean, 这些注解用于根据特定条件决定是否加载该配置类或其中的Bean`

注解作用示例解释
@ConditionalOnProperty当配置属性存在且匹配值时生效@ConditionalOnProperty(name=“cache.enabled”, havingValue=“true”)若 cache.enabled有值,且为true,才注入
@ConditionalOnClass当类路径存在指定类时生效@ConditionalOnClass(RedisTemplate.class)为了检测是否有该类,是否加了该依赖,没什么用
@ConditionalOnMissingBean当容器不存在指定 Bean 时生效@ConditionalOnMissingBean(DataSource.class)可以用于保底手段,当DataSource的Bean对象不存在或者注入失败,则可以手动创建一个返回
@Profile仅在指定 Profile 激活时生效@Profile(“production”)

区别

@Configuration: 明确告诉 Spring:我是一个配置类,我的主要目的是通过 @Bean 方法来定义和配置 Spring 容器管理的 Bean。请用 CGLIB 代理增强我,确保 @Bean 方法调用返回的是单例。

@Component: 告诉 Spring:我是一个需要被自动扫描并注册为 Bean 的组件类。它标记的类本身会被 Spring 实例化并管理为一个 Bean。

@Bean: 这是方法级别的注解。它用在 @Configuration 类或 @Component 类内部的方法上,告诉 Spring:调用我这个方法返回的对象,应该被注册为一个 Spring Bean。这个方法负责创建和配置这个 Bean 实例。

请添加图片描述

相关文章:

  • 做谷歌网站月饼营销软文
  • 做网站必须购买空间吗国外网站设计
  • 游戏周边产品 做网站济南seo外包服务
  • 常见的网站推广途径网络推广视频
  • b2b网站建设公司b站新人视频怎么推广
  • 用织梦模板做网站南京seo按天计费
  • c语言中的浮点类型
  • 细谈QT信号与槽机制
  • spring中的@Cacheable缓存
  • php后台增加权限控制
  • Odoo API 集成:XML-RPC 与 JSON-RPC 的比较
  • RabbitMq中启用NIO
  • 操作系统学习笔记 | 第一章 计算机系统概述
  • “ICU”归来的小鹏,如何抗衡小米YU7?
  • EJB知识
  • NCCN Guidelines Navigator:数智化工具引领肿瘤精准治疗新纪元
  • linux安装docker
  • 国内优秀wordpress主题推荐
  • 量学云讲堂2025朱永海慢牛开启第58期视频课程
  • 设计模式 | 工厂模式
  • 大模型推理-高通qnn基础
  • SpringMVC系列(三)(请求处理的十个实验(上))
  • MySQL常用函数性能优化及索引影响分析
  • PAC 学习框架:机器学习的可靠性工程
  • AI Agent模型:Plan-and-Execute、ReAct、Function Calling
  • leetcode-2138.将字符串划分为若干个长度为k的组