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

Spring IoC与DI详解:从Bean概念到手写实现

一、Spring Bean的概念与本质

1.1 什么是Bean?

在Spring框架中,Bean是一个由Spring IoC容器实例化、组装和管理的对象。Bean及其之间的依赖关系通过容器使用的配置元数据来定义。简单来说,Bean就是Spring容器管理的Java对象。简单来说,在Spring里,Bean就是由Spring容器创建、管理和装配的对象,容器负责它的生命周期(创建、初始化、销毁)和依赖注入,开发者无需手动new,直接用就行。

Bean的核心特征:

  • 由Spring容器创建和管理
  • 遵循依赖注入原则
  • 生命周期由容器控制
  • 可以通过名称或类型检索

1.2 Bean与普通Java对象的区别

特性普通Java对象Spring Bean
创建方式通过new关键字创建由Spring容器创建
依赖管理手动处理依赖关系容器自动处理依赖注入
生命周期由程序员控制由容器管理
作用域通常是单例支持多种作用域(singleton, prototype等)
配置方式硬编码在程序中通过配置元数据定义

1.3 Bean的配置元数据

Spring支持三种配置方式定义Bean:

  1. XML配置文件:传统的配置方式
  2. 注解配置:基于Java注解
  3. Java配置类:基于Java代码

本文将重点介绍XML配置方式实现IoC和DI。

二、基于XML的IoC容器实现

2.1 基础环境搭建

首先创建一个Maven项目,添加Spring核心依赖:

<dependencies><!-- Spring核心容器 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.10</version></dependency>
</dependencies>

2.2 创建Spring XML配置文件

在resources目录下创建applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 最基本的Bean定义 --><bean id="simpleBean" class="com.example.SimpleBean"/></beans>

2.3 创建并获取Bean

public class MainApp {public static void main(String[] args) {// 1. 加载Spring配置文件,创建容器ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 2. 获取Bean实例SimpleBean bean = (SimpleBean) context.getBean("simpleBean");// 3. 使用Beanbean.doSomething();}
}

三、依赖注入(DI)的实现方式

3.1 构造器注入

UserService.java

public class UserService {private UserRepository userRepository;// 构造器public UserService(UserRepository userRepository) {this.userRepository = userRepository;}public void saveUser(User user) {userRepository.save(user);}
}

applicationContext.xml

<bean id="userRepository" class="com.example.UserRepositoryImpl"/><bean id="userService" class="com.example.UserService"><constructor-arg ref="userRepository"/>
</bean>

3.2 Setter方法注入

OrderService.java

public class OrderService {private OrderDao orderDao;// Setter方法public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}
}

applicationContext.xml

<bean id="orderDao" class="com.example.OrderDaoImpl"/><bean id="orderService" class="com.example.OrderService"><property name="orderDao" ref="orderDao"/>
</bean>

3.3 字段注入(不推荐)

虽然可以通过字段注入,但推荐使用构造器注入:

<bean id="productService" class="com.example.ProductService"><property name="productDao" ref="productDao"/>
</bean>

四、Bean的作用域与生命周期

4.1 Bean的作用域

在XML中通过scope属性定义:

<!-- 单例模式(默认) -->
<bean id="singletonBean" class="com.example.SingletonBean" scope="singleton"/><!-- 原型模式(每次获取新实例) -->
<bean id="prototypeBean" class="com.example.PrototypeBean" scope="prototype"/><!-- Web相关作用域 -->
<bean id="requestBean" class="com.example.RequestBean" scope="request"/>
<bean id="sessionBean" class="com.example.SessionBean" scope="session"/>
<bean id="applicationBean" class="com.example.ApplicationBean" scope="application"/>

4.2 Bean的生命周期回调

方式一:实现接口

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

方式二:XML配置

<bean id="lifecycleBean" class="com.example.LifecycleBean"init-method="customInit" destroy-method="customDestroy"/>

五、集合类型的依赖注入

5.1 List注入

<bean id="collectionBean" class="com.example.CollectionBean"><property name="nameList"><list><value>张三</value><value>李四</value><value>王五</value></list></property>
</bean>

5.2 Map注入

<bean id="collectionBean" class="com.example.CollectionBean"><property name="userMap"><map><entry key="admin" value-ref="adminUser"/><entry key="guest" value-ref="guestUser"/></map></property>
</bean>

5.3 Properties注入

<bean id="dataSource" class="com.example.BasicDataSource"><property name="properties"><props><prop key="driver">com.mysql.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/test</prop><prop key="username">root</prop><prop key="password">123456</prop></props></property>
</bean>

六、自动装配(autowiring)配置

6.1 XML中的自动装配模式

<!-- 1. byName: 根据属性名匹配Bean ID -->
<bean id="customerService" class="com.example.CustomerService" autowire="byName"/><!-- 2. byType: 根据属性类型匹配Bean -->
<bean id="orderService" class="com.example.OrderService" autowire="byType"/><!-- 3. constructor: 构造器参数自动装配 -->
<bean id="paymentService" class="com.example.PaymentService" autowire="constructor"/><!-- 4. default/no: 不自动装配(默认) -->
<bean id="productService" class="com.example.ProductService" autowire="default"/>

6.2 自动装配的限制与解决方案

问题1:多个同类型Bean

<bean id="userDaoMySQL" class="com.example.UserDaoMySQLImpl"/>
<bean id="userDaoOracle" class="com.example.UserDaoOracleImpl"/><!-- 解决方案1:使用primary -->
<bean id="userDaoMySQL" class="com.example.UserDaoMySQLImpl" primary="true"/><!-- 解决方案2:使用autowire-candidate -->
<bean id="userDaoOracle" class="com.example.UserDaoOracleImpl" autowire-candidate="false"/>

问题2:必须依赖

<!-- 设置required=false允许依赖为null -->
<bean id="optionalService" class="com.example.OptionalService" autowire="byType"><property name="required" value="false"/>
</bean>

七、基于XML的AOP配置

7.1 配置AOP命名空间

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

7.2 定义切面

<!-- 1. 定义切面Bean -->
<bean id="loggingAspect" class="com.example.LoggingAspect"/><!-- 2. 配置AOP -->
<aop:config><!-- 定义切点 --><aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/><!-- 定义切面 --><aop:aspect ref="loggingAspect"><!-- 前置通知 --><aop:before pointcut-ref="serviceMethods" method="beforeAdvice"/><!-- 后置通知 --><aop:after-returning pointcut-ref="serviceMethods" method="afterReturningAdvice"returning="result"/></aop:aspect>
</aop:config>

八、Spring与第三方库集成

8.1 集成JDBC

<!-- 1. 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="123456"/>
</bean><!-- 2. 配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/>
</bean><!-- 3. 配置DAO -->
<bean id="userDao" class="com.example.UserDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

8.2 集成Hibernate

<!-- 1. 配置SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="hibernateProperties"><props><prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop></props></property><property name="packagesToScan" value="com.example.entity"/>
</bean><!-- 2. 配置事务管理器 -->
<bean id="transactionManager"class="org.springframework.orm.hibernate5.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/>
</bean><!-- 3. 启用注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

九、Spring测试框架集成

9.1 配置测试环境

<!-- 测试相关依赖 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.10</version><scope>test</scope>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope>
</dependency>

9.2 编写集成测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserServiceTest {@Autowiredprivate UserService userService;@Testpublic void testSaveUser() {User user = new User("test", "test@example.com");userService.saveUser(user);// 断言验证}
}

十、Spring XML配置代码案例

10.1 模块化配置

将大型配置文件拆分为多个小文件:

applicationContext.xml

<import resource="classpath:spring-datasource.xml"/>
<import resource="classpath:spring-service.xml"/>
<import resource="classpath:spring-dao.xml"/>

10.2 使用p命名空间简化配置

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userService" class="com.example.UserService"p:userRepository-ref="userRepository"/>
</beans>

10.3 使用SpEL表达式

<bean id="systemSettings" class="com.example.SystemSettings"><property name="appName" value="#{systemProperties['app.name']}"/><property name="maxUsers" value="#{T(java.lang.Integer).parseInt(systemProperties['max.users'])}"/>
</bean>

结语

通过本文的详细讲解,我们全面了解了Spring IoC容器和依赖注入机制在XML配置方式下的实现。从最基本的Bean定义到复杂的AOP配置,从简单的属性注入到集合类型的处理,XML配置方式提供了强大的灵活性和明确的配置结构。虽然现代Spring开发更倾向于使用注解和Java配置,但理解XML配置对于维护遗留系统和深入理解Spring原理仍然非常重要。

相关文章:

  • Spring Batch 专题系列(四):配置与调度 Spring Batch 作业
  • 分库分表-除了hash分片还有别的吗?
  • 算法思想之分治-快排
  • Java基础 4.15
  • PCL八叉树聚类
  • Python基础语法2
  • 游戏代码编辑
  • 凸优化第2讲:凸优化建模
  • 一篇文章快速上手linux系统中存储多路径multipath的配置
  • MCP、RAG与Agent:下一代智能系统的协同架构设计
  • Cribl 中数据脱敏mask 的实验
  • 【HDFS】BlockPlacementPolicyRackFaultTolerant#getMaxNode方法的功能及具体实例
  • BufferedReader 终极解析与记忆指南
  • 使用python求函数极限
  • Java实现选择排序算法
  • 盛水最多的容器问题详解:双指针法与暴力法的对比与实现
  • vcast工具env环境问题二:<command-line>: error: stray ‘\’ in program
  • 深入解析 sklearn 中的 LabelEncoder:功能、使用场景与注意事项
  • 三、The C in C++
  • TV板卡维修技术【一】
  • 人民网评:“中国传递爱而不是关税”
  • 一图看懂|特朗普政府VS美国顶尖高校:这场风暴如何刮起?
  • 九部门:将符合条件的家政从业人员纳入公租房等保障范围
  • 对话|女足国脚,离开体制“再就业”
  • 人事时间|商务部国际贸易谈判代表是什么职务,负责哪些工作?
  • 华勤技术回应H20政策调整:产业链已做充分准备,预计年营收维持20%以上增长