| 概念 | 本質 | 解決問題 |
|---|---|---|
| IoC (Inversion of Control) | 對象創建權從應用代碼移交給容器 | 解耦:類不再負責依賴的實例化 |
| DI (Dependency Injection) | 容器在創建對象時注入依賴 | 賦值:構造器/Setter/字段注入 |
兩者描述同一過程的不同視角:容器管理對象生命週期與依賴關係。
// 1. ClassPathXmlApplicationContext (XML 配置)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. AnnotationConfigApplicationContext (純註解配置)
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// 3. Web 環境:ContextLoaderListener 自動啟動,Controller 中 @Autowired 直接可用
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1. Setter 注入 -->
<bean id="student" class="com.example.Student">
<property name="id" value="1"/>
<property name="name" value="張三"/>
<property name="age" value="20"/>
</bean>
<!-- 2. 構造器注入 -->
<bean id="student2" class="com.example.Student">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="李四"/>
</bean>
<!-- 3. 引用其他 Bean (ref) -->
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
<bean id="userService" class="com.example.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 4. 生命週期回調 -->
<bean id="student3" class="com.example.Student"
init-method="init" destroy-method="destroy">
<property name="name" value="王五"/>
</bean>
</beans>
<beans xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="...
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example"/>
<!-- 等價於 + 掃描 -->
</beans>
或純 Java 配置:
@Configuration
@ComponentScan("com.example")
public class AppConfig { }
| 註解 | 語義層級 | 說明 |
|---|---|---|
| @Component | 通用 | 泛用組件,無特定業務含義 |
| @Repository | 持久層 | DAO,自動轉換數據訪問異常 |
| @Service | 業務層 | Service,標識業務邏輯組件 |
| @Controller | 表現層 | SpringMVC 控制器,配合 @RequestMapping |
本質上都是 @Component,語義化便於分層與 AOP 切點匹配。
@Service
public class UserServiceImpl implements UserService {
// 1. 字段注入 (簡潔但不利測試)
@Autowired
private UserDao userDao;
// 2. 構造器注入 (推薦:不可變、易測試、必要依賴明確)
private final UserDao userDao;
@Autowired // 單構造器可省略
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
// 3. Setter 注入 (可選依賴)
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
@Repository("mysqlDao")
public class MySqlUserDao implements UserDao { }
@Repository("oracleDao")
@Primary // 默認首選
public class OracleUserDao implements UserDao { }
@Service
public class UserServiceImpl {
@Autowired
@Qualifier("mysqlDao") // 強制指定
private UserDao userDao;
}
| 作用域 | 含義 | Web 環境 |
|---|---|---|
| singleton (默認) | 容器中單例 | 單例 |
| prototype | 每次獲取新實例 | 每次請求新實例 |
| request | - | 每個 HTTP 請求一個實例 |
| session | - | 每個 HTTP Session 一個實例 |
| application | - | 每個 ServletContext 一個實例 |
| 維度 | XML | 註解 |
|---|---|---|
| 侵入性 | 零侵入 (POJO) | 需引入 Spring 註解 |
| 可讀性 | 集中式,適合大型團隊 | 分散在代碼中,IDE 支持好 |
| 重構友好 | 修改配置文件 | 重構工具自動更新 |
| 環境隔離 | 多套配置文件切換 | Profile + @Conditional |
| 趨勢 | 維護模式 | 主流、Spring Boot 默認 |
建議:新項目首選註解 + Java Config;基礎設施類 (DataSource、TransactionManager) 可用 XML/Java Config 集中管理。
// Dao
@Repository
public class UserDaoImpl implements UserDao { ... }
// Service
@Service
public class UserServiceImpl implements UserService {
private final UserDao userDao;
public UserServiceImpl(UserDao userDao) { this.userDao = userDao; }
public User login(String u, String p) { return userDao.findByUsername(u); }
}
// Controller
@Controller
@RequestMapping("/user")
public class UserController {
private final UserService userService;
public UserController(UserService userService) { this.userService = userService; }
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password, Model model) {
User user = userService.login(username, password);
if (user != null) { model.addAttribute("user", user); return "welcome"; }
return "login";
}
}
Spring 核心就這麼簡單:容器負責 new,你負責用。