深入理解控制反转和Spring容器
IoC(Inversion of Control,控制反转)是 Spring 框架的核心概念之一。它将对象的创建、配置和生命周期管理的控制权从应用程序代码转移到了 Spring 容器。
// 传统方式:程序主动创建对象
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 紧耦合
public void saveUser() {
userDao.save();
}
}
// IoC 方式:容器注入对象
public class UserService {
private UserDao userDao; // 松耦合
// 通过构造器或 setter 注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void saveUser() {
userDao.save();
}
}不要主动去找依赖对象,而是让容器把依赖对象"注入"进来。这样可以降低组件之间的耦合度,提高代码的可测试性和可维护性。
BeanFactory 是 Spring IoC 容器的基础接口,提供了完整的 IoC 服务。
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class BeanFactoryDemo {
public static void main(String[] args) {
// 加载配置文件
ClassPathResource resource =
new ClassPathResource("beans.xml");
// 创建 BeanFactory
BeanFactory factory = new XmlBeanFactory(resource);
// 获取 Bean(此时才创建对象)
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
}
}ApplicationContext 是 BeanFactory 的子接口,提供了更多企业级功能。
// 1. ClassPathXmlApplicationContext
// 从类路径加载配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. FileSystemXmlApplicationContext
// 从文件系统加载配置文件
ApplicationContext context =
new FileSystemXmlApplicationContext("c:/config/beans.xml");
// 3. AnnotationConfigApplicationContext
// 基于注解的配置
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// 4. WebApplicationContext
// Web 应用专用(由 Spring MVC 自动创建)传统的配置方式,通过 XML 文件定义 Bean:
<?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 id="userService" class="com.example.service.UserServiceImpl">
<!-- 注入依赖 -->
<property name="userDao" ref="userDao"/>
</bean>
</beans>使用注解简化配置:
// 配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// 可以在这里定义额外的 Bean
}
// DAO 层
@Repository
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("保存用户");
}
}
// Service 层
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public void saveUser() {
userDao.save();
}
}@Configuration
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean
public UserService userService() {
UserServiceImpl service = new UserServiceImpl();
service.setUserDao(userDao());
return service;
}
}Spring 支持多种 Bean 作用域:
| 作用域 | 说明 |
|---|---|
| singleton | 单例模式(默认),整个容器中只有一个实例 |
| prototype | 原型模式,每次获取都创建新实例 |
| request | 每个 HTTP 请求创建一个实例(Web 环境) |
| session | 每个 HTTP Session 创建一个实例(Web 环境) |
| application | 每个 ServletContext 创建一个实例(Web 环境) |
// XML 方式
<bean id="user" class="com.example.User" scope="prototype"/>
// 注解方式
@Component
@Scope("prototype")
public class User {
// ...
}1. ApplicationContext 和 BeanFactory 的主要区别是?
2. Spring Bean 的默认作用域是?