文章目录
- 引言
- 一、什么是IOC(控制反转)
-
- [1.1 IOC的核心概念](#1.1 IOC的核心概念)
- [1.2 IOC与DI的关系](#1.2 IOC与DI的关系)
- [1.3 IOC带来的好处](#1.3 IOC带来的好处)
- 二、Bean的声明方式详解
-
- [2.1 XML配置文件方式(经典方式)](#2.1 XML配置文件方式(经典方式))
- [2.2 注解方式(现代主流)](#2.2 注解方式(现代主流))
- [2.3 Java配置类方式(类型安全)](#2.3 Java配置类方式(类型安全))
- [2.4 混合使用策略](#2.4 混合使用策略)
- 三、IOC容器的工作流程深度解析
-
- [3.1 第一阶段:IOC容器初始化](#3.1 第一阶段:IOC容器初始化)
-
- [3.1.1 流程图解](#3.1.1 流程图解)
- [3.1.2 详细过程分析](#3.1.2 详细过程分析)
- [3.1.3 BeanDefinition的创建过程示例](#3.1.3 BeanDefinition的创建过程示例)
- [3.2 第二阶段:Bean初始化及依赖注入](#3.2 第二阶段:Bean初始化及依赖注入)
-
- [3.2.1 流程图解](#3.2.1 流程图解)
- [3.2.2 Bean的完整生命周期](#3.2.2 Bean的完整生命周期)
- [3.2.3 依赖注入的三种方式](#3.2.3 依赖注入的三种方式)
- [3.2.4 BeanPostProcessor的强大扩展能力](#3.2.4 BeanPostProcessor的强大扩展能力)
- [3.3 第三阶段:Bean的使用与管理](#3.3 第三阶段:Bean的使用与管理)
-
- [3.3.1 Bean的获取方式](#3.3.1 Bean的获取方式)
- [3.3.2 Bean作用域详解](#3.3.2 Bean作用域详解)
- [3.3.3 条件化Bean配置](#3.3.3 条件化Bean配置)
- 四、高级特性与最佳实践
-
- [4.1 循环依赖的解决](#4.1 循环依赖的解决)
- [4.2 延迟初始化策略](#4.2 延迟初始化策略)
- [4.3 工厂Bean的使用](#4.3 工厂Bean的使用)
- [4.4 Bean的生命周期回调](#4.4 Bean的生命周期回调)
- 五、性能优化与常见问题
-
- [5.1 性能优化建议](#5.1 性能优化建议)
- [5.2 常见问题与解决方案](#5.2 常见问题与解决方案)
- 六、实战案例:电商系统IOC设计
- 总结
引言
在当今的企业级Java应用开发中,Spring框架无疑是最受欢迎的框架之一。而Spring框架的核心------IOC(控制反转)容器,更是理解Spring精髓的关键所在。本文将深入剖析Spring IOC容器的依赖注入全过程,带你领略这一革命性设计思想的魅力所在。
一、什么是IOC(控制反转)
1.1 IOC的核心概念
控制反转(Inversion of Control) 是一种颠覆传统编程模式的设计思想。在传统的程序设计中,对象的创建和依赖关系的管理由应用程序代码主动控制;而在IOC模式下,这种控制权被反转给了容器。
举个生活中的例子:传统方式就像你自己去市场买菜、洗菜、切菜、炒菜(全程自己控制);而IOC模式更像是去餐厅点菜,你只需要告诉服务员想吃什么(声明需求),餐厅后厨(容器)会帮你准备好一切。
1.2 IOC与DI的关系
很多初学者容易混淆IOC和DI(依赖注入)的概念,这里做一个清晰的区分:
- IOC:是一种更宏观的设计思想,强调控制权的反转
- DI:是IOC思想的一种具体实现方式,通过容器注入依赖
可以说,DI是实现IOC的主要手段,但并非唯一方式。在Spring框架中,我们主要使用依赖注入来实现控制反转。
1.3 IOC带来的好处
java
// 传统方式:紧耦合
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 直接new,高度耦合
public void addUser(User user) {
userDao.save(user);
}
}
// IOC方式:松耦合
public class UserService {
@Autowired
private UserDao userDao; // 依赖由容器注入
public void addUser(User user) {
userDao.save(user);
}
}
核心优势:
- 降低耦合度:组件间依赖关系由容器管理
- 提高可测试性:便于进行单元测试和模拟
- 增强可维护性:配置集中管理,易于修改
- 提升复用性:组件可被多个应用共享使用
二、Bean的声明方式详解
Spring提供了多种灵活的方式来声明和配置Bean,满足不同场景的需求。
2.1 XML配置文件方式(经典方式)
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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 基本Bean定义 -->
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
<!-- 带属性的Bean -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- 构造器注入 -->
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userDao"/>
<constructor-arg value="default"/>
</bean>
<!-- Setter注入 -->
<bean id="orderService" class="com.example.service.OrderServiceImpl">
<property name="userService" ref="userService"/>
<property name="timeout" value="5000"/>
</bean>
</beans>
XML配置的特点:
- 集中管理:所有配置在一个或几个文件中
- 与代码解耦:修改配置无需重新编译
- 可读性强:结构清晰,适合复杂配置
- 支持热更新:部分场景下可动态刷新
2.2 注解方式(现代主流)
java
// 1. 组件扫描配置
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
// 2. Service层
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired // 自动注入
private UserDao userDao;
@Value("${app.default.name}") // 注入配置值
private String defaultName;
@PostConstruct
public void init() {
System.out.println("UserService初始化完成");
}
@PreDestroy
public void destroy() {
System.out.println("UserService准备销毁");
}
}
// 3. Dao层
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public User findById(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new UserRowMapper(),
id
);
}
}
// 4. 控制器层
@Controller
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
@ResponseBody
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
常用注解分类:
| 注解 | 作用 | 说明 |
|---|---|---|
@Component |
通用组件 | 最基础的组件注解 |
@Service |
服务层组件 | 业务逻辑层 |
@Repository |
数据访问层 | 数据访问层,自动异常转换 |
@Controller |
控制层 | MVC控制器 |
@RestController |
REST控制器 | 包含@Controller和@ResponseBody |
@Configuration |
配置类 | 定义配置信息 |
@Autowired |
自动注入 | 按类型自动注入 |
@Qualifier |
指定Bean名 | 与@Autowired配合使用 |
@Resource |
资源注入 | JDK注解,可按名称注入 |
@Value |
值注入 | 注入简单值或表达式 |
2.3 Java配置类方式(类型安全)
java
@Configuration
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource dataSource(
@Value("${db.url}") String url,
@Value("${db.username}") String username,
@Value("${db.password}") String password) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaximumPoolSize(20);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
@Scope("prototype") // 原型模式
@Lazy // 懒加载
public UserService userService(UserDao userDao) {
return new UserServiceImpl(userDao);
}
@Bean
public UserDao userDao(JdbcTemplate jdbcTemplate) {
UserDaoImpl userDao = new UserDaoImpl();
userDao.setJdbcTemplate(jdbcTemplate);
return userDao;
}
}
Java配置的优势:
- 类型安全:编译时检查,避免配置错误
- IDE友好:自动补全和重构支持
- 便于调试:可直接在代码中打断点
- 条件化配置 :结合
@Conditional实现灵活配置
2.4 混合使用策略
在实际项目中,推荐混合使用各种配置方式:
java
@Configuration
@Import({DataSourceConfig.class, CacheConfig.class}) // 导入其他配置类
@ImportResource("classpath:legacy-beans.xml") // 导入XML配置
@ComponentScan(basePackages = "com.example.service")
public class MainConfig {
// 新功能使用Java配置
@Bean
public NewFeatureService newFeatureService() {
return new NewFeatureServiceImpl();
}
}
三、IOC容器的工作流程深度解析
Spring IOC容器的工作流程可以分为三个核心阶段,每个阶段都有其独特的职责和实现机制。
3.1 第一阶段:IOC容器初始化
这个阶段是容器启动的核心,主要完成Bean定义的加载和注册。
3.1.1 流程图解
启动ApplicationContext
↓
加载配置资源
↓
创建BeanDefinitionReader
↓
读取并解析配置
↓
生成BeanDefinition对象
↓
注册到BeanDefinitionRegistry
↓
初始化完成,进入下一阶段
3.1.2 详细过程分析
1. 资源定位与加载
java
// Spring容器的启动入口
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 或者使用注解方式
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
2. BeanDefinition的创建
Spring将每个Bean的配置信息解析为BeanDefinition对象,这是一个重要的数据结构:
java
// BeanDefinition接口的主要方法
public interface BeanDefinition {
// Bean的类名
void setBeanClassName(String beanClassName);
String getBeanClassName();
// 作用域
void setScope(String scope);
String getScope();
// 是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 依赖的Bean名称
void setDependsOn(String... dependsOn);
String[] getDependsOn();
// 是否单例
boolean isSingleton();
// 是否原型
boolean isPrototype();
// 工厂方法
void setFactoryMethodName(String factoryMethodName);
String getFactoryMethodName();
// 初始化方法
void setInitMethodName(String initMethodName);
String getInitMethodName();
// 销毁方法
void setDestroyMethodName(String destroyMethodName);
String getDestroyMethodName();
// 属性值
MutablePropertyValues getPropertyValues();
}
3. 注册到容器
Spring使用BeanDefinitionRegistry来管理所有的BeanDefinition:
java
// 核心注册表接口
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
void removeBeanDefinition(String beanName);
BeanDefinition getBeanDefinition(String beanName);
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
}
// 实际实现:DefaultListableBeanFactory
public class DefaultListableBeanFactory implements BeanDefinitionRegistry {
// 使用ConcurrentHashMap存储BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<>(256);
// 按类型存储Bean名称
private final Map<Class<?>, String[]> allBeanNamesByType =
new ConcurrentHashMap<>(64);
}
3.1.3 BeanDefinition的创建过程示例
以XML配置为例:
xml
<!-- XML配置 -->
<bean id="userService" class="com.example.UserServiceImpl"
scope="singleton" lazy-init="false">
<property name="userDao" ref="userDao"/>
<property name="defaultName" value="admin"/>
</bean>
被解析为:
java
// 创建RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.example.UserServiceImpl");
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
beanDefinition.setLazyInit(false);
// 设置属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("userDao", new RuntimeBeanReference("userDao"));
propertyValues.addPropertyValue("defaultName", "admin");
beanDefinition.setPropertyValues(propertyValues);
// 注册到容器
registry.registerBeanDefinition("userService", beanDefinition);
3.2 第二阶段:Bean初始化及依赖注入
这个阶段是IOC容器的核心执行阶段,完成Bean的实例化、依赖注入和初始化。
3.2.1 流程图解
获取BeanDefinition
↓
实例化Bean(createBeanInstance)
↓
处理BeanPostProcessor(实例化前)
↓
属性注入(populateBean)
↓
处理Aware接口
↓
BeanPostProcessor前置处理
↓
执行初始化方法
↓
BeanPostProcessor后置处理
↓
Bean准备就绪
3.2.2 Bean的完整生命周期
java
// Bean的完整生命周期(简化版)
public class BeanLifecycleDemo implements
BeanNameAware, BeanFactoryAware, ApplicationContextAware,
InitializingBean, DisposableBean {
private String name;
// 1. 实例化(构造函数)
public BeanLifecycleDemo() {
System.out.println("1. 构造函数执行 - 实例化Bean");
}
// 2. 属性设置(Setter方法)
public void setName(String name) {
System.out.println("2. 属性设置 - name: " + name);
this.name = name;
}
// 3. BeanNameAware接口
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware - beanName: " + name);
}
// 4. BeanFactoryAware接口
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("4. BeanFactoryAware - 设置BeanFactory");
}
// 5. ApplicationContextAware接口
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
System.out.println("5. ApplicationContextAware - 设置ApplicationContext");
}
// 6. BeanPostProcessor.postProcessBeforeInitialization
// 7. @PostConstruct注解方法
@PostConstruct
public void postConstruct() {
System.out.println("7. @PostConstruct - 注解初始化方法");
}
// 8. InitializingBean.afterPropertiesSet
@Override
public void afterPropertiesSet() {
System.out.println("8. InitializingBean - afterPropertiesSet");
}
// 9. init-method配置的方法
public void customInit() {
System.out.println("9. init-method - 自定义初始化方法");
}
// 10. BeanPostProcessor.postProcessAfterInitialization
// 11. Bean准备就绪,可使用
public void doSomething() {
System.out.println("11. Bean业务方法执行");
}
// 12. @PreDestroy注解方法
@PreDestroy
public void preDestroy() {
System.out.println("12. @PreDestroy - 注解销毁方法");
}
// 13. DisposableBean.destroy
@Override
public void destroy() {
System.out.println("13. DisposableBean - destroy方法");
}
// 14. destroy-method配置的方法
public void customDestroy() {
System.out.println("14. destroy-method - 自定义销毁方法");
}
}
3.2.3 依赖注入的三种方式
1. 构造器注入(推荐)
java
@Component
public class OrderService {
private final UserService userService;
private final ProductService productService;
// 构造器注入
@Autowired
public OrderService(UserService userService, ProductService productService) {
this.userService = userService;
this.productService = productService;
}
}
优点:
- 保证依赖不可变(final字段)
- 保证依赖不为null
- 保证完全初始化的状态
- 避免循环依赖问题
- 易于测试
2. Setter注入
java
@Component
public class OrderService {
private UserService userService;
private ProductService productService;
// Setter注入
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
}
适用场景:
- 可选依赖
- 需要重新配置的依赖
- 有默认实现的依赖
3. 字段注入
java
@Component
public class OrderService {
@Autowired
private UserService userService;
@Autowired
private ProductService productService;
}
注意:虽然字段注入写法简洁,但存在以下问题:
- 不能声明为final
- 隐藏依赖关系
- 不利于测试
- Spring团队不推荐使用
3.2.4 BeanPostProcessor的强大扩展能力
BeanPostProcessor是Spring提供的重要扩展点,可以在Bean初始化前后进行自定义处理:
java
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Before初始化: " + beanName + " - " + bean.getClass().getName());
// 示例:为特定类型的Bean添加代理
if (bean instanceof UserService) {
System.out.println("为UserService创建代理");
return Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("调用方法: " + method.getName());
return method.invoke(bean, args);
}
);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("After初始化: " + beanName + " - " + bean.getClass().getName());
// 示例:检查Bean的属性
if (bean instanceof Validatable) {
((Validatable) bean).validate();
}
return bean;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE; // 执行顺序
}
}
3.3 第三阶段:Bean的使用与管理
3.3.1 Bean的获取方式
1. 依赖注入(推荐)
java
@Component
public class OrderController {
// 按类型注入
@Autowired
private OrderService orderService;
// 按名称注入
@Autowired
@Qualifier("specialOrderService")
private OrderService specialService;
// 构造器注入(Spring 4.3+可以省略@Autowired)
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
// 集合注入
@Autowired
private List<Validator> validators;
// Map注入(key为bean名称)
@Autowired
private Map<String, Processor> processors;
}
2. 编程式获取
java
// 通过ApplicationContext获取
@Component
public class BeanLocator {
@Autowired
private ApplicationContext context;
public Object getBeanByName(String name) {
return context.getBean(name);
}
public <T> T getBeanByType(Class<T> type) {
return context.getBean(type);
}
public <T> Map<String, T> getBeansOfType(Class<T> type) {
return context.getBeansOfType(type);
}
// 获取所有Bean名称
public String[] getAllBeanNames() {
return context.getBeanDefinitionNames();
}
}
3. 延迟查找
java
@Component
public class LazyBeanLookup {
// 延迟注入(当使用时才获取)
@Autowired
private ObjectProvider<ExpensiveService> expensiveServiceProvider;
public void doWork() {
// 按需获取
ExpensiveService service = expensiveServiceProvider.getIfAvailable();
if (service != null) {
service.process();
}
}
}
3.3.2 Bean作用域详解
Spring支持多种Bean作用域:
java
@Configuration
public class ScopeConfig {
// 单例(默认) - 整个容器只有一个实例
@Bean
@Scope("singleton") // 或 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public SingletonBean singletonBean() {
return new SingletonBean();
}
// 原型 - 每次获取都创建新实例
@Bean
@Scope("prototype") // 或 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
// Request作用域(Web环境)
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public RequestScopedBean requestScopedBean() {
return new RequestScopedBean();
}
// Session作用域(Web环境)
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public SessionScopedBean sessionScopedBean() {
return new SessionScopedBean();
}
// 自定义作用域
@Bean
public CustomScope customScope() {
return new CustomScope();
}
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
return beanFactory -> {
beanFactory.registerScope("custom", customScope());
};
}
@Bean
@Scope("custom")
public CustomScopedBean customScopedBean() {
return new CustomScopedBean();
}
}
3.3.3 条件化Bean配置
Spring提供了强大的条件化配置机制:
java
@Configuration
public class ConditionalConfig {
// 根据条件创建Bean
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public CacheService redisCacheService() {
return new RedisCacheService();
}
@Bean
@ConditionalOnMissingBean(CacheService.class)
public CacheService localCacheService() {
return new LocalCacheService();
}
// 自定义条件
@Bean
@Conditional(ProductionCondition.class)
public DataSource productionDataSource() {
return createProductionDataSource();
}
@Bean
@Conditional(DevelopmentCondition.class)
public DataSource developmentDataSource() {
return createDevelopmentDataSource();
}
// 配置类条件
@Configuration
@ConditionalOnWebApplication
@ConditionalOnProperty(prefix = "security", name = "enabled", matchIfMissing = true)
@EnableWebSecurity
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
// 安全配置
}
}
// 自定义条件类
public class ProductionCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return "production".equals(env.getProperty("app.env"));
}
}
四、高级特性与最佳实践
4.1 循环依赖的解决
Spring通过三级缓存巧妙解决了单例Bean的构造器循环依赖问题:
java
// 循环依赖示例
@Component
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
// Spring的三级缓存解决方案
public class DefaultSingletonBeanRegistry {
// 一级缓存:存放完全初始化好的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:存放早期暴露的Bean(未完成属性注入)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 三级缓存:存放Bean工厂,用于创建早期引用
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 正在创建中的Bean
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
解决流程:
- 创建ServiceA,放入三级缓存
- ServiceA需要ServiceB,开始创建ServiceB
- ServiceB需要ServiceA,从三级缓存获取ServiceA的早期引用
- ServiceB创建完成,注入到ServiceA
- ServiceA完成创建
4.2 延迟初始化策略
java
@Configuration
public class LazyConfig {
// 懒加载Bean
@Bean
@Lazy
public ExpensiveBean expensiveBean() {
System.out.println("创建ExpensiveBean...");
return new ExpensiveBean();
}
// 配置类懒加载
@Configuration
@Lazy
public static class LazySubConfig {
@Bean
public AnotherBean anotherBean() {
return new AnotherBean(); // 只有被请求时才创建
}
}
// 条件化懒加载
@Bean
@Lazy
@ConditionalOnMissingBean
public DefaultService defaultService() {
return new DefaultService();
}
}
4.3 工厂Bean的使用
FactoryBean用于创建复杂的对象:
java
@Component
public class ConnectionFactoryBean implements FactoryBean<Connection> {
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Override
public Connection getObject() throws Exception {
// 创建复杂的连接对象
return DriverManager.getConnection(url, username, password);
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false; // 每次获取新连接
}
}
// 使用FactoryBean
@Component
public class DataAccessService {
@Autowired
private Connection connection; // 实际获取的是FactoryBean.getObject()
// 如果需要获取FactoryBean本身
@Autowired
private ConnectionFactoryBean connectionFactoryBean;
// 或者通过名称获取
@Autowired
@Qualifier("&connectionFactoryBean") // &前缀表示获取FactoryBean本身
private FactoryBean<Connection> factoryBean;
}
4.4 Bean的生命周期回调
java
@Component
public class LifecycleBean implements
SmartLifecycle,
ApplicationListener<ContextRefreshedEvent> {
private volatile boolean running = false;
// 1. 容器刷新完成事件
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("容器刷新完成,开始初始化业务...");
initBusiness();
}
// 2. SmartLifecycle - 启动
@Override
public void start() {
if (!running) {
System.out.println("LifecycleBean开始启动...");
running = true;
// 启动后台线程等
}
}
// 3. SmartLifecycle - 停止
@Override
public void stop() {
if (running) {
System.out.println("LifecycleBean正在停止...");
running = false;
// 清理资源
}
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return 0; // 执行阶段
}
@Override
public boolean isAutoStartup() {
return true; // 自动启动
}
private void initBusiness() {
// 业务初始化逻辑
}
}
五、性能优化与常见问题
5.1 性能优化建议
-
合理使用作用域
- 无状态Bean使用单例
- 有状态Bean考虑原型
- Web相关Bean使用request/session作用域
-
懒加载策略
java@Configuration @Lazy // 整个配置类懒加载 public class LazyConfig { @Bean @Lazy(false) // 这个Bean不懒加载 public EssentialBean essentialBean() { return new EssentialBean(); } } -
避免过度使用AOP
java// 精确指定切点,避免匹配过多方法 @Pointcut("execution(public * com.example.service.*.*(..))") public void serviceLayer() {} -
合理使用缓存
java@Component @CacheConfig(cacheNames = "users") public class UserService { @Cacheable(key = "#id") public User getUser(Long id) { // 数据库查询 } @CachePut(key = "#user.id") public User updateUser(User user) { // 更新数据库 } @CacheEvict(key = "#id") public void deleteUser(Long id) { // 删除数据库记录 } }
5.2 常见问题与解决方案
问题1:Bean创建失败
java
// 原因:循环依赖(构造器注入)
@Component
public class A {
private final B b;
public A(B b) { this.b = b; } // 错误:循环依赖
}
@Component
public class B {
private final A a;
public B(A a) { this.a = a; } // 错误:循环依赖
}
// 解决方案1:使用Setter注入
@Component
public class A {
private B b;
@Autowired
public void setB(B b) { this.b = b; }
}
// 解决方案2:使用@Lazy
@Component
public class A {
private final B b;
public A(@Lazy B b) { this.b = b; } // 延迟注入
}
问题2:多个同类型Bean
java
// 多个同类型Bean
@Bean
public DataSource primaryDataSource() { ... }
@Bean
public DataSource secondaryDataSource() { ... }
// 解决方案1:使用@Primary
@Bean
@Primary
public DataSource primaryDataSource() { ... }
// 解决方案2:使用@Qualifier
@Autowired
@Qualifier("secondaryDataSource")
private DataSource dataSource;
// 解决方案3:使用@Resource(按名称)
@Resource(name = "secondaryDataSource")
private DataSource dataSource;
问题3:Bean覆盖问题
java
// 在application.properties中控制
spring.main.allow-bean-definition-overriding=true
// 或者明确指定Bean名称
@Bean("myDataSource")
public DataSource dataSource() { ... }
六、实战案例:电商系统IOC设计
java
// 领域模型
@Entity
@Data
public class Product {
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
}
// 仓储层
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByPriceLessThan(BigDecimal price);
}
// 服务层
@Service
@Transactional
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Autowired
private InventoryService inventoryService;
@Autowired
private PriceCalculator priceCalculator;
@Autowired
private List<Validator> validators; // 策略模式
public Product createProduct(Product product) {
// 验证
validators.forEach(v -> v.validate(product));
// 计算价格
BigDecimal finalPrice = priceCalculator.calculate(product);
product.setPrice(finalPrice);
// 保存
return productRepository.save(product);
}
@Async // 异步处理
@EventListener
public void handleOrderEvent(OrderCreatedEvent event) {
updateInventory(event.getProductId(), event.getQuantity());
}
}
// 配置类
@Configuration
@EnableAsync
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
@EnableCaching
public class AppConfig {
@Bean
public PriceCalculator priceCalculator(
@Value("${tax.rate}") BigDecimal taxRate,
@Value("${discount.enabled}") boolean discountEnabled) {
return new PriceCalculator(taxRate, discountEnabled);
}
@Bean
@Order(1)
public Validator stockValidator() {
return product -> {
if (product.getStock() < 0) {
throw new ValidationException("库存不能为负");
}
};
}
@Bean
@Order(2)
public Validator priceValidator() {
return product -> {
if (product.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
throw new ValidationException("价格必须大于0");
}
};
}
// 条件化配置:开发环境
@Bean
@Profile("dev")
public DataSource devDataSource() {
return DataSourceBuilder.create()
.url("jdbc:h2:mem:testdb")
.username("sa")
.password("")
.build();
}
// 条件化配置:生产环境
@Bean
@Profile("prod")
public DataSource prodDataSource(
@Value("${db.url}") String url,
@Value("${db.username}") String username,
@Value("${db.password}") String password) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaximumPoolSize(50);
return dataSource;
}
}
总结
Spring IOC容器通过其精妙的设计和实现,为我们提供了一套完整的依赖管理解决方案。从Bean的声明、注册、初始化到使用,每一个环节都体现了Spring框架的设计哲学:约定优于配置 、面向接口编程 、关注点分离。
关键要点回顾:
- IOC是思想,DI是实现:理解控制反转和依赖注入的关系
- 多种配置方式:XML、注解、Java配置各有适用场景
- 完整的生命周期:从BeanDefinition到销毁,每个阶段都可定制
- 强大的扩展点:BeanPostProcessor、FactoryBean等提供无限可能
- 灵活的作用域:适应不同应用场景的需求
- 优雅的循环依赖解决:三级缓存机制的精妙设计
掌握Spring IOC容器的原理和实践,不仅能帮助我们更好地使用Spring框架,更能提升我们的系统设计能力和架构思维。在实际项目中,应根据具体需求选择合适的配置方式和设计模式,充分发挥IOC容器的优势。
如需获取更多关于Spring IoC容器深度解析、Bean生命周期管理、循环依赖解决方案、条件化配置等内容,请持续关注本专栏《Spring核心技术深度剖析》系列文章。