Boot 集成:条件判读、用户替换与组件责任
业务服务需要SQL、Redis、消息和HTTP客户端,Boot负责把满足条件的基础设施接入容器;它没有替业务决定提交、幂等、鉴权和恢复协议。本文固定 Boot4.0.9 / Framework7.0.10 / JDK21,安全运行线为Security7.0.8。旧Boot3.3.3的候选发现与退让机制见启动正文,运行配置来源见EX1。本篇研究集成启用和替换,组件内部机制仍只有一个权威讲解。
启动成功、条件匹配与业务成功
先区分三类证据:类路径中有驱动;条件匹配并登记了定义;真实调用取得业务需要的结果。KafkaTemplate Bean存在不代表broker接收过消息,MongoClient构造完成不代表目标数据库已选择正确,Health为UP也不代表跨资源下单不变量成立。
构建使用4.0.9 parent/BOM,按需要声明官方starter。例如JDBC用spring-boot-starter-jdbc与运行时com.mysql:mysql-connector-j,Redis用spring-boot-starter-data-redis,Mongo映射用spring-boot-starter-data-mongodb,阻塞HTTP客户端用spring-boot-starter-restclient。声明之后仍要检查实际依赖树、配置对象和条件报告;BOM不会自动引入全部组件。完整可运行工程和依赖分组见本票实验,不要把不同profile的产物当同一次类路径。
判读顺序是 候选注册 → 类/属性/已有Bean条件 → 定义与候选选择 → 实例创建 → 外部请求 → 业务不变量。用同类型用户Bean替换某个默认实现,可能只影响这一层;下游的模板、事务管理器或观测器仍可继续装配。反过来,两份用户实现若没有明确Primary,ConditionalOnSingleCandidate可能不成立,依赖它的模板便消失。不能用“Boot总会选一个”解释。
JDBC:连接信息、单候选与用户数据源
没有用户DataSource时,DataSourceAutoConfiguration先核查JDBC类和不存在的R2DBC ConnectionFactory,再选择嵌入库或池。Hikari分支要求相应类、缺DataSource,并允许spring.datasource.type选择。URL、驱动、用户名来自连接配置,池自身的毫秒等待、容量来自spring.datasource.hikari.*;来源优先级仍按EX1,不从仓库文件猜运行值。
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/?connectTimeout=3000&socketTimeout=3000&sslMode=DISABLED&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=
spring.datasource.hikari.maximum-pool-size=2
spring.datasource.hikari.minimum-idle=0
spring.datasource.hikari.connection-timeout=500这是本机隔离教学配置,空密码与关闭TLS只用于已经确认的本机测试连接;部署使用经确认的身份、信任和凭据注入。配置最大2只限制该实例这一池的借用,不是全库连接预算。用户提供DataSource时,默认池因条件不登记;JdbcTemplate只要仍有单个可选DataSource,仍可以引用用户数据源。声明自定义JdbcTemplate又会使其对应默认模板退让。替换DataSource与排除整份JDBC自动配置不是同一操作:后者可能连连接详情、初始化及关联能力一起移走。
固定DataSource条件源码中,缺R2DBC ConnectionFactory、缺DataSource/XADataSource和池类型选择是不同分支。多数据源需要明确路由、事务管理器与映射,不靠开放同名覆盖补救;事务资源正文解释连接绑定与提交责任。验证要检查模板实际指向哪个数据源,再执行目标库的有限SQL;H2能跑不证明MySQL锁语义。
MongoDB:连接前缀、工厂与映射分开
Boot4的连接项是spring.mongodb.*,映射/GridFS等仍在spring.data.mongodb.*。例如:
spring.mongodb.uri=mongodb://127.0.0.1:27017/u24_catalog?connectTimeoutMS=3000&serverSelectionTimeoutMS=3000
spring.data.mongodb.auto-index-creation=falseMongoAutoConfiguration负责MongoClient/settings/连接详情;DataMongoAutoConfiguration在其后组合MongoDatabaseFactory、模板、转换器等。用户MongoClient使默认client方法退让;用户MongoDatabaseFactory还能使驱动层配置的类条件退让。用户MongoClientSettings会影响默认settings及标准customizer的登记,不能假定“URI照常完全覆盖用户settings”。
这里最容易被默认值掩盖:把URI写成旧spring.data.mongodb.uri,本机默认localhost仍可达,PING照样成功。必须读取实际连接详情和工厂的database名称,使用明确的非默认合成库名;再做有限调用。数据库名可在不写集合时检查,若写测试文档,仅清本票拥有的资源。现有U03的24日连接PASS保留为历史事实;本票修正其未来YAML前缀,新的复验与旧证据分开。固定定义见MongoProperties与DataMongoProperties。文档模型、复制与事务能力仍回MongoDB主题。
Elasticsearch还需按服务端选客户端线。本机8.19.23沿U03使用8.19.23客户端;Boot4默认ES自动配置面向Rest5客户端,在8.x-only类路径上它不是"条件不匹配"的优雅退让,而是配置类内省直接NoClassDefFoundError(缺Rest5ClientTransport)。自定义8.x客户端因此是绕开默认自动配置的显式适配:讲清默认链无法评估、URL实际绑定、低层传输关闭责任和info验证,不能宣称"默认starter自动兼容ES8"。固定客户端条件和Rest5条件给出这条边界。
Redis:模板按名退让,工厂按类型替换
Redis连接仍使用spring.data.redis.*。Lettuce分支看客户端类、client-type与是否已有RedisConnectionFactory;默认ConnectionFactory与模板是不同替换点。显式端口/数据库、connect-timeout和command timeout各有等待对象,不能都叫“Redis超时”。
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.database=13
spring.data.redis.connect-timeout=2s
spring.data.redis.timeout=2s原码:v4.0.9 DataRedisAutoConfiguration中的两个模板方法,连续节选。
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}默认redisTemplate以名称判缺失,同时要求单个可选factory;StringRedisTemplate的方法级无参数MissingBean按返回类型推断。注册一个名为tenantTemplate的同类型对象,不必阻止名为redisTemplate的默认定义;两个factory且无Primary,则单候选条件又可能否决模板。错误处理应从具体注解条件出发,不能套用“有用户同类型Bean就全部退让”的口号。
验证读取factory实际database/端口,再PING;只有默认localhost能连不足以证明参数被绑定。替换factory时负责认证、拓扑、SSL与连接资源关闭,模板的key/value序列化仍是另外的契约。缓存/Session共享Redis连接不等于共享同一个数据协议;不要把序列化字节当成可直接互读的字符串。
缓存:先有拦截器,再选 CacheManager
加cache starter不会自动让任意方法变成缓存。CacheAutoConfiguration还要求CacheAspectSupport(例如@EnableCaching产生的拦截基础设施),并且缺CacheManager及名为cacheResolver的Bean。随后按明确spring.cache.type或可用provider选manager;若classpath发生变化,默认选择也可能变化。
@Configuration(proxyBeanMethods = false)
@EnableCaching
class CacheConfig {
// 用户CacheManager使Boot的默认选择退让。
@Bean CacheManager cacheManager() {
return new ConcurrentMapCacheManager("u24Catalog");
}
}以上是需要Configuration/Bean、EnableCaching、CacheManager、ConcurrentMapCacheManager相应导入的独立配置类;默认选择对照可删除用户Bean并显式设置:
spring.cache.type=redis
spring.cache.cache-names=u24Catalog
spring.cache.redis.time-to-live=30s
spring.cache.redis.key-prefix=u24:catalog:Redis连接条件仍须满足。TTL是该manager的默认配置,不是数据库回写协议;自定义RedisCacheConfiguration/BuilderCustomizer又可改变序列化与过期策略。反例是切换到ConcurrentMap后仍以为30s Redis TTL有效,或没有进入缓存代理却归因于Redis故障。代理、自调用、sync与null语义由缓存权威正文统一解释;Boot集成验证要先识别真实manager、实际键和TTL,再谈命中。
消息:四种接线和确认边界
四种集成需要分别核对,不将Kafka的配置名字套在RabbitMQ/JMS/Pulsar上。下面都是Boot4对应模块的最小接线输入;本票条件实验若未连接broker,证明的只是实际框架的装配/退让,发送、持久化与消费确认仍须各自真实实验。
Kafka。 使用spring-boot-starter-kafka,KafkaAutoConfiguration要求KafkaTemplate类;ProducerFactory、ConsumerFactory、KafkaTemplate各按自身MissingBean分别退让。用户producer factory不必使consumer factory消失。配置示例:
spring.kafka.bootstrap-servers=127.0.0.1:9092
spring.kafka.client-id=u24-conditions
spring.kafka.listener.auto-startup=false
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer事务管理器还有spring.kafka.producer.transaction-id-prefix条件,不是加starter便产生业务事务。关闭监听auto-startup只是避免本票fixture启动消费者,不表示消息可用;KafkaTemplate方法返回的future仍需按Kafka交付原理观察确认。
RabbitMQ。 spring-boot-starter-amqp需要RabbitTemplate与Rabbit Channel类,默认factory、RabbitOperations/template和admin分支不同;template还要求单个ConnectionFactory。最小本机配置为:
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.listener.simple.auto-startup=false
spring.rabbitmq.listener.direct.auto-startup=false
spring.rabbitmq.dynamic=false这里不声明真实broker凭据,也不运行队列创建;正式实验使用自身有权的独有vhost/队列。dynamic=false影响自动admin,不能当作停发开关。用户RabbitOperations可使默认template退让,多个factory无Primary又可能令template缺失;confirm、return、ack分别由broker交付课与U48/U58验证。
JMS。 spring-boot-starter-jms只给JMS框架集成;JmsAutoConfiguration还要求已有ConnectionFactory Bean。ActiveMQ/Artemis客户端提供者是另外的依赖与配置,不能把spring.jms.*当作broker地址。例如Artemis需要相应starter并声明:
spring.artemis.mode=native
spring.artemis.broker-url=tcp://127.0.0.1:61616
spring.jms.listener.auto-startup=false未安装broker时,只能给实际JmsTemplate条件/用户factory替换fixture,不能假造发送日志或把Kafka结果补成JMS实测。JMS会话事务不自动与JDBC绑定;调度/JMS原文原有未运行标记保留。
Pulsar。 spring-boot-starter-pulsar根据PulsarClient/PulsarTemplate类启用,再分别提供client factory、producer/consumer factory、template和listener factory;事务还需对应开关。
spring.pulsar.client.service-url=pulsar://127.0.0.1:6650
spring.pulsar.listener.auto-startup=false这些参数只说明客户端连接目标和监听启动,不能推出topic已创建、订阅存在或成功确认。自建factory要验证默认定义退让并关闭客户端线程;broker故障、重投/事务/观测由U48逐版本验收。四者具体装配分支可查本票scope列出的固定源码,不用一种“消息starter”概括四个协议。
安全:过滤链与凭据源分别退让
Security7.0.8随4.0.9 BOM运行,旧6.3.3机制文仍独立。Servlet默认链以是否已有SecurityFilterChain判断是否退让;默认用户源又核查AuthenticationManager、AuthenticationProvider、UserDetailsService等,不能说“自定义链自动替换所有认证源”。仅提供自定义UserDetailsService也不自动写出正确的端点授权规则。
spring-boot-starter-security加在Web应用中会改变默认访问行为,Actuator又有自己的默认管理安全配置。使用自定义管理链时,必须补业务兜底链,具体可运行配置、401/403与CSRF边界在Actuator权威讲解。先确认选中哪条链、谁校验凭据、谁裁决资源权限,再看响应码;不要用测试中直接setAuthentication替代认证器真实工作。普通SecurityFilterChain Bean退让与同名覆盖仍是不同机制。
Session:仓库接管与受控命名空间
Web容器原生HttpSession与Spring Session Repository不是同一层。Boot4使用Session专用starter选择实现:spring-boot-starter-session-data-redis或spring-boot-starter-session-jdbc;Redis分支需相应连接工厂、Web类型和缺用户SessionRepository,JDBC分支要求Servlet、DataSource和缺用户仓库。不要同时放进多种实现却不说明选择条件,更不要沿旧版本猜store-type参数。
spring.session.timeout=60s
spring.session.data.redis.namespace=u24:session:replace-with-run-id
spring.session.data.redis.repository-type=default
spring.session.data.redis.configure-action=none实验必须用每次独有namespace;configure-action=none避免indexed实现默认通知配置改变用户Redis全局设置。default repository与indexed repository的索引/清理/通知能力不同,禁配置动作不能宣称已验indexed过期通知。用户SessionRepository会接管仓库选择,Filter仍可继续为该仓库读写cookie与会话;验证同一cookie的保存/读取、用户仓库Bean身份和默认Redis定义是否退让,而不只看启动日志。
会话保存时点、序列化、maxInactiveInterval与并发丢更新有独立语义;该集成不等于登录撤销协议,HTTP身份线程清理也不等于删除session。Security机制文说明身份生命周期,完整Session映射/过期/并发由U44承接。清理只删除本票实际创建的会话ID/key,不能FLUSHDB,也不能为通过测试修改Redis通知全局配置。
HTTP 客户端:定制优先于替换 Builder
Boot4阻塞与响应式客户端分别由restclient/webclient模块接线;应用类型为Servlet并不禁止使用响应式客户端,但不应把它改称WebFlux服务。RestClient自动提供prototype Builder,每次注入得到经过Configurer配置的实例;Configurer会应用请求工厂、SSL和有序customizers。用户直接定义Builder使默认builder方法退让,也承担保留这些配置的责任。
@Bean
org.springframework.boot.restclient.RestClientCustomizer publicHeader() {
return builder -> builder.defaultHeader("X-Application", "u24-lab");
}需要一个header时,优先定制;替换整个builder再RestClient.builder()可能丢掉自动观测。确需替换时使用配置器的configure方法,并重验超时、SSL及trace传播。不要共享一个可变builder在多个线程反复改baseUrl。原码中的观测customizer只负责构造回调,不是向任意裸客户端自动注入拦截器:
*/
@AutoConfiguration
@ConditionalOnClass({ RestClient.class, ObservationRestClientCustomizer.class, ObservationRegistry.class,
ObservationProperties.class })
@ConditionalOnBean({ RestClient.Builder.class, ObservationRegistry.class })
@EnableConfigurationProperties(ObservationProperties.class)
public final class RestClientObservationAutoConfiguration {
@Bean
RestClientCustomizer observationRestClientCustomizer(ObservationRegistry observationRegistry,
ObjectProvider<ClientRequestObservationConvention> customConvention,
ObservationProperties observationProperties) {
String name = observationProperties.getHttp().getClient().getRequests().getName();
ClientRequestObservationConvention observationConvention = customConvention
.getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));
return new ObservationRestClientCustomizer(observationRegistry, observationConvention);
}真正应用customizers发生在默认builder的Configurer路径。真实HTTP测试应对照自动builder与裸RestClient.create(),由下游读取header/traceparent;实例类型与Bean数量不足以证明跨进程传播。连接、deadline、取消与重试机制回HTTP客户端正文,trace采样与出口范围回Actuator篇。
条件报告、错误配置与资源归还
排障用条件报告回答“为什么定义没登记”,用异常链回答“为什么实例没建好”,用实际客户端设置和目标响应回答“连到了谁”。--debug可输出报告,但报告与env/configprops可能含部署细节,公开方式按Actuator权限与脱敏控制,不把它当任意公网调试接口。
| 输入/症状 | 先收集什么 | 修复后验证 |
|---|---|---|
| 用户Bean存在,默认仍出现 | MissingBean按名称还是类型、泛型/返回类型、处理顺序 | 检查默认定义不登记、唯一实际实例或明确多实例选择 |
| 两数据源后模板消失 | SingleCandidate与Primary、条件否决原因 | 模板引用目标库,有限SQL与事务管理器对应 |
| Mongo默认本机能连,指定库名没生效 | Boot4前缀、连接详情、工厂database名字 | 改正确键后读非默认设置,重启复验 |
| 裸JMS没有JmsTemplate | 类路径和ConnectionFactory Bean | 补对应provider或明确用户factory;不能用任意假Bean抵扣broker行为 |
| 替换HTTP builder后无trace | customizers/configurer是否应用、下游收到的header | 自动builder对照,检查真实trace关联而非只看本地日志 |
| 退出后仍有线程/连接 | 谁创建client/pool、是否纳入destroy/close、未完成请求 | 关闭Context后资源退出;异常清理也完成,外部提交另核对 |
用户提供Bean并不意味着Boot不再负责调用容器销毁回调;应该明确该Bean的关闭方法,避免同时关闭底层共享连接或漏掉自建传输。失败清理不是跨资源回滚,重启前后业务状态仍须由对应组件协议和幂等/Outbox核对。
容量、版本和恢复责任
假设60服务、每服务4实例、每池最大10连接,总上界2400;默认池变30则7200。自定义第二个DataSource而原池未退让,或某模板误连另一工厂,既可能超预算也可能把数据写到错误库。统一自动配置使团队接入成本低;用户Bean定制能表达专用池/拓扑,却增加生命周期、版本和监控责任。选择要附依赖树、实际实例身份、资源预算、失败与回退证据,不能靠“统一starter规范”免除复验。
缓存选择也有成本:本地manager延迟低、依赖少,但多实例失效需业务协议;Redis manager可共享缓存状态,却增加网络、序列化、过期和Redis故障耦合。Session集中存储利于跨实例读取,但缓存TTL不等于身份撤销及时性;把通知配置打开去追求过期事件,还会扩大对共享Redis的运维责任。
升级4.0.x或改变classpath时,先保持业务不变量和兼容约束,再复跑条件/替换与真实客户端调用。ES8专用适配不因“Boot BOM已更新”便可无声换成9.x;数据库/消息确认语义也不能靠Bean装配测试覆盖。恢复应保留旧制品与明确配置版本;数据迁移后的二进制回退是否可行由迁移协议决定。
实验入口与证明分层
公开入口是boot-readiness实验。工程把条件probe、真实Actuator服务、Redis Session和ES8适配分开,避免一个类路径自动启动全部组件。正式运行证据按每场景记录输入、退出、实际值、定义退让、请求结果与清理;本篇只在相应结果完成后声明已运行。条件probe用实际Boot/组件类,不把fixture替换为真实broker交付。
本票源码/配置范围固定,实际运行观察见实验说明与docs/audits/java-depth-u24-verification.md。JPA/Hibernate归U43,响应式服务/R2DBC归U27,Data映射/Session完整语义归U44,消息深层集成归U48及broker票,测试切片/上下文缓存归U25,镜像/平台部署归U65/U66;这些仍是承诺范围,不登记X来减少分母。
闭卷验收
本页 12 道闭卷题收进了下方自测面板:先回忆,再展开参考答案与评分点,最后给三档自评。