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

Java——Spring 非注解开发:IoC/DI 与 Bean 管理实战(含第三方组件整合)

在 Spring 框架的学习中,基于 XML 的非注解开发模式是理解框架底层机制的核心路径。本文结合黑马程序员 SSM 教程内容,系统解析 IoC(控制反转)、DI(依赖注入)的核心原理,深度演示 Bean(含第三方组件)的配置与管理,并通过企业级案例展现实战技巧。

一、IoC(控制反转):从手动创建到容器托管

1. 核心思想与容器本质​

IoC 的核心是将对象的创建与生命周期管理从代码中剥离,交由 Spring 容器统一处理。传统开发中通过new关键字创建对象,而在 IoC 模式下,开发者只需在 XML 中声明 Bean,由容器通过反射、工厂模式等机制生成实例。Spring 提供BeanFactory(基础容器)和ApplicationContext(增强容器,支持国际化、事件机制)两种实现,企业开发中通常使用后者。

2. Bean 定义的三种方式

(1)无参构造函数(默认方式)

<bean id="userService" class="com.service.UserServiceImpl"/>

容器通过反射调用类的无参构造方法实例化对象,适用于大多数简单场景。

(2)静态工厂方法

<bean id="car" class="com.factory.StaticCarFactory" factory-method="createCar"/>

通过factory-method指定静态方法创建对象,适用于需要复用复杂创建逻辑的场景。

(3)实例工厂方法

<bean id="carFactory" class="com.factory.InstanceCarFactory"/><bean id="car" factory-bean="carFactory" factory-method="createCar"/>

需先定义工厂 Bean,再通过factory-bean指定实例工厂,适用于工厂本身需要注入其他依赖的场景。

3. 容器操作核心代码

// 初始化容器(加载XML配置)​
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取Bean(两种方式)​
UserService userService1 = (UserService) context.getBean("userService");UserService userService2 = context.getBean("userService", UserService.class);

二、DI(依赖注入):解耦对象依赖关系

1. 两种核心注入方式

(1)构造函数注入(适合依赖关系固定的场景)

<bean id="userService" class="com.service.UserServiceImpl"><constructor-arg name="userDao" ref="userDao"/> <!-- 按顺序注入引用类型 --><constructor-arg name="timeout" value="3000"/> <!-- 按名称注入基本类型 --></bean>

(2)Setter 方法注入(适合依赖关系可变的场景)

<bean id="userService" class="com.service.UserServiceImpl"><property name="userDao" ref="userDao"/> <!-- 注入引用类型 --><property name="version" value="1.0"/> <!-- 注入基本类型 -->
</bean>

2. 高级注入技巧

(1)集合类型注入(支持 List/Set/Map/Props)

<bean id="roleService" class="com.service.RoleServiceImpl"><property name="adminRoles"><list><value>ROLE_ADMIN</value><value>ROLE_SUPER</value></list></property><property name="userProps"><props><prop key="timeout">3000</prop><prop key="retries">3</prop></props></property>
</bean>

(2)自动装配(Autowiring)

通过autowire属性简化配置,常用模式:​

  • byName:按属性名匹配 Bean 的id​
  • byType:按属性类型匹配唯一 Bean(需保证容器中该类型唯一)
<bean id="userService" class="com.service.UserServiceImpl" autowire="byType"/>

3. 第三方 Bean 的依赖注入

以数据库连接池 Druid 为例,演示如何注入第三方组件的复杂配置:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/> <!-- 注入JDBC驱动 --><property name="url" value="${jdbc.url}"/> <!-- 注入数据库URL --><property name="maxActive" value="20"/> <!-- 注入连接池参数 --></bean>

关键点: 第三方 Bean 的属性需与类中的 Setter 方法严格对应(如setDriverClassName对应driverClassName属性)。

三、Bean 管理:生命周期、作用域与高级特性

1. 生命周期控制(初始化与销毁回调)​

(1)XML 配置方式(推荐)​

<bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource"​init-method="init" <!-- 初始化方法 -->​destroy-method="close"> <!-- 销毁方法(仅单例Bean生效) --><!-- 配置省略 --></bean>

(2)接口实现方式(侵入性强,不推荐)​

public class UserService implements InitializingBean, DisposableBean {@Overridepublic void afterPropertiesSet() throws Exception {// 初始化逻辑​}@Overridepublic void destroy() throws Exception {// 销毁逻辑​}}

2. 作用域控制(4 大核心作用域)

作用域说明典型场景
singleton容器中唯一实例(默认),线程安全,适用于无状态 Bean(Service/DAO)业务逻辑层、数据访问层
prototype每次获取创建新实例,非线程安全,适用于有状态 Bean(命令对象)需保存用户状态的组件
request每次 HTTP 请求创建新实例(仅 Web 环境)Web 层请求参数处理器
session每个 HTTP 会话共享一个实例(仅 Web 环境)会话级缓存组件
<bean id="userSession" class="com.SessionBean" scope="session"/> <!-- Web环境专用 -->

3. 第三方 Bean 的继承与别名​

(1)配置继承(复用公共参数)

<!-- 定义基础数据源配置 -->
<bean id="baseDataSource" abstract="true"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/>
</bean>
<!-- 子类继承并扩展 -->
<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" parent="baseDataSource"><property name="username" value="${jdbc.master.user}"/>
</bean>

(2)别名定义(简化 Bean 引用)

<alias name="userService" alias="userServiceProxy"/> <!-- 为同一Bean定义多个名称 -->

四、企业级实战:SSM 整合与第三方组件深度集成​

1. SSM 框架核心整合步骤(XML 版)​

(1)Spring 与 MyBatis 整合

<!-- 1. 配置数据源(Druid-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/>
</bean>
<!-- 2. 配置SqlSessionFactoryMyBatis第三方Bean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath:mapper/*.xml"/> <!-- 映射文件路径 -->
</bean>
<!-- 3. 扫描Mapper接口(自动生成代理Bean-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.dao"/> <!-- Mapper接口所在包 -->
</bean>

(2)Spring 与 SpringMVC 整合

<!-- web.xml配置DispatcherServlet -->
<servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param>
</servlet>
<!-- springmvc.xml配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/>
</bean>

2. 复杂场景:多数据源动态切换(以 Druid 为例)​

(1)定义目标数据源

<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource"><!-- 主库配置 -->
</bean>
<bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource"><!-- 从库配置 -->
</bean>

(2)配置动态数据源路由(Spring 原生支持)

<bean id="dynamicDataSource" class="org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource"><property name="targetDataSources"><map key-type="java.lang.String"><entry key="master" value-ref="masterDataSource"/><entry key="slave" value-ref="slaveDataSource"/></map></property><property name="defaultTargetDataSource" ref="masterDataSource"/> <!-- 默认数据源 -->
</bean>

(3)实现数据源切换逻辑(线程安全)

public class DataSourceContextHolder {private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();public static void setDataSourceType(String type) {CONTEXT_HOLDER.set(type);}public static String getDataSourceType() {return CONTEXT_HOLDER.get();}
}

3. 第三方日志框架(Log4j)整合

<!-- 配置ConsoleAppender(输出到控制台) -->
<bean id="consoleAppender" class="org.apache.log4j.ConsoleAppender"><property name="layout" ref="patternLayout"/> <!-- 注入日志格式 -->
</bean>
<bean id="patternLayout" class="org.apache.log4j.PatternLayout"><property name="conversionPattern" value="%d [%t] %-5p %c - %m%n"/> <!-- 日志模板 -->
</bean>
<!-- 配置根Logger(关联Appender-->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"><property name="targetClass" value="org.apache.log4j.Logger"/><property name="targetMethod" value="getRootLogger"/><property name="arguments"><list><value>INFO</value> <!-- 日志级别 --><ref bean="consoleAppender"/> <!-- 关联Appender --></list></property>
</bean>

五、非注解模式的优缺点与适用场景​

1. 核心优势​

  • 配置可见性:所有 Bean 定义集中在 XML,依赖关系一目了然,适合复杂依赖场景。​
    兼容性:可无缝整合不支持注解的老旧系统或第三方库(如遗留数据库驱动、传统日志框架)。​
  • 学习价值:深入理解 Spring 底层机制(反射、工厂模式、容器生命周期)的最佳实践。​

2. 局限性​

  • 配置冗余:大量 XML 标签导致文件臃肿,修改时需频繁切换上下文。​
    类型安全问题:编译期无法检查配置错误(如class路径错误、属性名拼写错误),需运行时验证。​
  • 维护成本:复杂继承关系可能导致配置混乱,团队协作时需严格规范命名与结构。​

3. 适用场景​

  • 遗留系统迁移:逐步将传统 JavaEE 项目纳入 Spring 生态,避免大规模代码改动。​
  • 基础设施管理:数据源、事务管理器、缓存框架等底层组件的配置,适合在 XML 中统一管理。​
  • 教学与底层研究:理解 Spring IoC/DI 核心原理,必须掌握 XML 配置模式。​

六、总结:从 XML 到注解的演进与融合​

非注解开发模式是 Spring 的 “基石”,其核心是通过 XML 文件显式定义 Bean 的行为与依赖关系。尽管现代开发以注解(@Component/@Autowired)为主流,但 XML 在以下场景仍不可替代:​

  • 第三方组件整合:当第三方库不支持注解或需要复杂初始化参数时,XML 是最直接的配置方式。​
  • 全局配置管理:如多数据源、事务​
http://www.lqws.cn/news/536869.html

相关文章:

  • python的银行柜台管理系统
  • easyExcel导入多sheet的Excel,存在合并单元格、列不固定的情况
  • # RK3588 Linux SDK 完整问题解决记录-编译内核头文件
  • 【Pandas】pandas DataFrame first_valid_index
  • 跨越十年的C++演进:C++14新特性全解析
  • 手机控车远程启动一键启动
  • C++智能指针概念及std::unique_ptr使用介绍
  • 使用docker搭建redis主从架构,一主2从
  • day48-硬件学习之GPT定时器、UART及I2C
  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(4):2022年12月2023年12月
  • 机器学习18-强化学习RLHF
  • python基于协同过滤的动漫推荐系统
  • 华为云Flexus+DeepSeek征文|一键部署知识库搜索增强版搭建AI Agent
  • 《仿盒马》app开发技术分享-- 逻辑优化第三弹(83)
  • 新手向:Neo4j的安装与使用
  • 供应链数据可视化大屏
  • OneCode框架 Tree 相关注解使用说明
  • 服务器的安装与安全设置 域环境的搭建和管理 Windows基本配置 网络服务常用网络命令的应用 安全管理Windows Server 2019
  • 独立开发还能做吗
  • Git-git worktree的使用
  • 测试方法的分类
  • recipes的版本比较老如何更新到新版本?
  • 板凳-------Mysql cookbook学习 (十--11)
  • AAAI 2025论文分享│面向生物医学的具有像素级洞察力的多模态大语言模型
  • day43 打卡
  • Redis主从架构哨兵模式
  • Rk3568驱动开发_Key驱动_13
  • Flink部署与应用——Flink架构概览
  • 如何在 Manjaro Linux 上启用 AUR 仓库来安装软件包
  • 关于如何在 Git 中切换到之前创建的分支的方法