0%

Spring Bean 的继承与依赖:复用配置与控制实例化顺序

在 Spring 中,Bean 的继承和依赖是两种重要的配置机制。继承用于复用配置(减少重复代码),依赖用于控制 Bean 的实例化顺序。详细解析这两种机制的实现方式、使用场景及注意事项。

Bean 的继承:复用配置,减少冗余

Spring 中的 Bean 继承并非 Java 中的类继承(不涉及类的父子关系),而是配置的继承:子 Bean 可以继承父 Bean 的所有配置(属性、依赖等),并可覆盖父 Bean 的配置。这类似于 “模板模式”,父 Bean 定义通用配置,子 Bean 仅需定义差异化部分。

1. 基本使用:通过 parent 属性实现继承

(1)普通 Bean 作为父 Bean

父 Bean 可以是一个可实例化的普通 Bean,子 Bean 通过 parent 属性指定父 Bean 的 id,从而继承其配置。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 父 Bean:定义通用配置 -->
<bean id="parentPerson" class="com.zhanghe.study.spring4.beans.beantest.Person">
<property name="name" value="张三"/> <!-- 通用属性:姓名 -->
<property name="car" ref="car"/> <!-- 通用依赖:Car 对象 -->
<property name="cars"> <!-- 通用集合:List<Car> -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
</bean>

<!-- 子 Bean:继承父 Bean 并覆盖部分配置 -->
<bean id="sonPerson" parent="parentPerson">
<!-- 覆盖父 Bean 的 name 属性 -->
<property name="name" value="张飞"/>
<!-- 继承父 Bean 的 car、cars 配置,无需重复定义 -->
</bean>
阅读全文 »

Spring 配置 Bean 全指南:从 XML 到注解的完整实践

Spring 配置 Bean 的核心目标是将 Bean 的创建、依赖管理交给 IOC 容器,通过 XML 或注解定义 Bean 的元数据(如类名、依赖、生命周期),最终由容器统一实例化并装配。从 “XML 配置” 到 “注解配置”,系统拆解 Bean 的配置方式、依赖注入逻辑、自动装配规则及歧义性处理,同时对比两种配置方式的优缺点与最佳实践。

XML 配置 Bean:传统且灵活的配置方式

XML 是 Spring 早期最主流的 Bean 配置方式,支持复杂的 Bean 定义(如工厂 Bean、集合属性),适合需要明确配置流程的场景。其核心是通过 <bean> 标签定义 Bean,配合 <property>/<constructor-arg> 注入依赖。

1. 基础 Bean 配置:构造器与 Setter 注入

Spring 实例化 Bean 主要依赖构造器(默认无参构造器),依赖注入(DI)分为 Setter 注入(属性注入)和 构造器注入,分别对应不同的使用场景。

(1)Setter 注入(最常用)

核心原理:Spring 先通过无参构造器实例化 Bean,再调用属性的 setter 方法注入依赖。
关键要求:Bean 类必须提供无参构造器(若未显式定义任何构造器,JVM 会默认生成;若显式定义有参构造器,需手动添加无参构造器)。

1.1 简单类型注入(value 属性)

注入基本类型(String、int、double 等)或字符串,使用 value 属性:

1
2
3
4
5
6
<!-- 配置 HelloWorld Bean,Setter 注入 name 属性 -->
<bean id="helloWorld" class="com.zhanghe.study.spring4.beans.helloworld.HelloWorld">
<!-- name:对应 setName() 方法(去掉 set 后首字母小写,与成员变量名无关) -->
<!-- value:注入简单类型值 -->
<property name="name" value="Spring Hello"/>
</bean>

对应的 Java 类:

阅读全文 »

Spring 容器深度解析:从 BeanFactory 到 ApplicationContext 的体系与实践

Spring 容器是 IOC(控制反转)思想的具体实现,核心职责是管理 Bean 的生命周期(创建、装配、销毁)与依赖关系,是 Spring 框架的 “心脏”。Spring 提供了两类核心容器:BeanFactory(基础容器)和 ApplicationContext(高级容器),二者在功能、初始化策略和适用场景上存在显著差异。从 “容器体系→核心实现→关键区别→Bean 定义元数据” 四个维度,彻底拆解 Spring 容器的工作机制。

Spring 容器体系总览

Spring 容器基于 “分层设计”,从基础到高级形成完整体系,核心接口与实现类的关系如下:

spring容器

核心设计思路:BeanFactory 定义基础规范,ApplicationContext 在其之上扩展高级功能,满足不同场景需求(轻量级 vs 企业级)。

基础容器:BeanFactory 详解

BeanFactory 是 Spring 容器的顶层接口,定义了 IOC 容器的最小功能集 ——“获取 Bean、判断 Bean 状态”,是 Spring 框架内部使用的基础容器(面向框架基础设施)。

1. BeanFactory 核心接口与方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface BeanFactory {
// 关键常量:区分 FactoryBean 本身与它生成的对象(前缀 "&")
String FACTORY_BEAN_PREFIX = "&";

// 1. 获取 Bean(核心方法,支持按名称、类型、带参数构造)
Object getBean(String name) throws BeansException; // 按名称获取(返回 Object,需强转)
<T> T getBean(String name, Class<T> requiredType) throws BeansException; // 按名称+类型(无需强转)
Object getBean(String name, Object... args) throws BeansException; // 带构造参数(创建原型 Bean 时用)
<T> T getBean(Class<T> requiredType) throws BeansException; // 按类型获取(推荐,更类型安全)
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException; // 按类型+构造参数

// 2. 判断 Bean 状态
boolean containsBean(String name); // 容器中是否存在该名称的 Bean
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; // 是否为单例(默认)
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; // 是否为原型(每次 getBean 新建)
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; // Bean 类型是否匹配
Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 获取 Bean 的类型
String[] getAliases(String name); // 获取 Bean 的别名(一个 Bean 可多个别名)
}
关键方法解析:
  • FACTORY_BEAN_PREFIX = "&":特殊前缀,用于获取FactoryBean本身(而非其生成的对象)。例如:
    • getBean("userFactory"):获取 userFactory 这个 FactoryBean 生成的 User 对象;
    • getBean("&userFactory"):获取 userFactory 这个 FactoryBean 实例本身。
  • getBean 重载:支持多种获取方式,按类型获取(getBean(Class<T>))是最常用的,避免强转,更安全。
  • 单例 / 原型判断isSingletonisPrototype 对应 Bean 的 scope 配置(默认单例)。

2. BeanFactory 的核心子类

BeanFactory 接口本身不实现具体逻辑,其功能通过三个核心子类扩展:

阅读全文 »

MySQL 表结构修改全解析:从编码到列定义

在数据库维护过程中,修改表结构是常见操作,包括调整编码、修改列名、增减字段等。MySQL 提供了丰富的 ALTER TABLE 语句支持这些操作,本文详细讲解各类修改场景的语法和注意事项。

修改编码格式(数据库 / 表 / 字段)

编码格式不匹配可能导致中文乱码或表情存储失败,需根据需求调整为 utf8utf8mb4(支持表情)。

1. 修改数据库编码

1
2
-- 语法:ALTER DATABASE 数据库名 CHARACTER SET 编码 [COLLATE 校对规则];
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  • 影响:新表默认使用该编码,已有表不受影响。

2. 修改表编码

1
2
-- 语法:ALTER TABLE 表名 CHARACTER SET 编码 [COLLATE 校对规则];
ALTER TABLE users CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  • 影响:表的默认编码更新,新添加的字段会继承该编码,已有字段需单独修改。

3. 修改字段编码

1
2
-- 语法:ALTER TABLE 表名 MODIFY 字段名 类型 CHARACTER SET 编码 [COLLATE 校对规则];
ALTER TABLE users MODIFY nickname VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
阅读全文 »

XML 命名空间:解决命名冲突的核心机制

在复杂的 XML 文档中,尤其是需要整合多个来源的 XML 片段(如不同标准、不同系统的配置)时,元素或属性重名的情况极为常见。例如,<table>元素在 HTML 中表示表格,在数据库 XML 中可能表示数据表,这种命名冲突会导致解析歧义。XML 命名空间(XML Namespace) 正是为解决此类问题而生,它通过为元素和属性分配唯一的 “命名空间标识”,明确区分相同名称的不同含义。

XML 命名空间的核心概念

  • 命名空间:本质是一个唯一的标识符(通常是 URI,如http://www.springframework.org/schema/beans),用于标识一组 XML 元素和属性的 “归属”。
  • 前缀(Prefix):简化命名空间使用的短别名(如contextmvc),通过前缀与命名空间 URI 绑定,避免在每个元素中重复书写长 URI。
  • 默认命名空间:未指定前缀的元素默认归属的命名空间,简化文档书写。

命名空间的声明方式

XML 命名空间通过xmlns属性声明,有两种核心形式:带前缀的命名空间默认命名空间

带前缀的命名空间(显式声明)

通过xmlns:prefix="URI"的形式声明,其中:

阅读全文 »