承接上篇 Hello World,本文展示 Spring 如何通過 @ComponentScan 實現 Bean 自動發現、自動裝配,完全擺脫 XML 與 @Bean 手動聲明。
com.websystique.spring ├── configuration/AppConfig.java # 掃描配置 ├── dao/EmployeeDao.java # 持久層介面 ├── dao/EmployeeDaoImpl.java # @Repository ├── service/DateService.java # 業務介面 ├── service/DateServiceImpl.java # @Service ├── service/EmployeeService.java # 核心業務介面 ├── service/EmployeeServiceImpl.java # @Service + @Autowired ├── model/Employee.java # 實體 └── AppMain.java # 啟動
@Configuration
@ComponentScan(basePackages = "com.websystique.spring")
public class AppConfig {
// 空類體!所有 Bean 由掃描自動發現
}
@ComponentScan 掃描基礎包下所有類,識別標註刻板印象註解的類作為 Bean:
| 註解 | 語義層級 | 說明 |
|---|---|---|
@Repository | 持久層 (DAO) | 自動轉換持久化異常 |
@Service | 業務層 | 標識業務邏輯組件 |
@Controller | 表現層 (MVC) | Web 請求處理 |
@Component | 通用組件 | 上述三者的父註解,泛用 |
@Configuration | 配置類 | 內部亦含 @Component |
最佳實踐: 嚴格按層級使用對應註解,而非濫用 @Component,利於架構治理與 AOP 切點精準匹配。
<beans xmlns:context="https://www.springframework.org/schema/context" ...> <context:component-scan base-package="com.websystique.spring" /> </beans>
@Repository("employeeDao")
public class EmployeeDaoImpl implements EmployeeDao {
public void saveInDatabase(Employee employee) {
System.out.println("Employee " + employee.getName() +
" registered for assessment on " + employee.getAssessmentDate());
}
}
@Service("dateService")
public class DateServiceImpl implements DateService {
public LocalDate getNextAssessmentDate() {
return new LocalDate(2015, 10, 10);
}
}
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
@Autowired private DateService dateService;
@Autowired private EmployeeDao employeeDao;
public void registerEmployee(Employee employee) {
employee.setAssessmentDate(dateService.getNextAssessmentDate());
employeeDao.saveInDatabase(employee);
}
}
@Autowired 按類型自動裝配。因掃描已註冊 dateService、employeeDao Bean,容器能精準注入。
AbstractApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.scan("com.websystique.spring"); // 程式化掃描
context.refresh(); // 必須刷新完成註冊
EmployeeService service = context.getBean("employeeService", EmployeeService.class);
AbstractApplicationContext context =
new ClassPathXmlApplicationContext("app-config.xml");
Employee Danny Theys is registered for assessment on 2016-12-22
@ComponentScan 掃描類路徑,識別刻板印象註解。@Autowired 注入點在 Bean 初始化階段按類型/名稱解析依賴。AnnotationConfigApplicationContext 整合掃描、註冊、刷新、生命週期管理。後續將探討:Bean 作用域、生命週期回調、@Primary/@Qualifier 解決多候選衝突、條件裝配 (@Conditional)。