在 Spring 2.5.6 之前,整合 Hibernate 需在 sessionFactory 中顯式配置 mappingResources 或 annotatedClasses,每新增一個實體類就要修改 XML,極易遺漏、難維護:
<!-- 傳統痛苦配置 -->
<property name="annotatedClasses">
<list>
<value>com.pplus.model.User</value>
<value>com.pplus.model.Order</value>
<value>com.pplus.model.Product</value>
<!-- 每新增實體必須手動添加 -->
</list>
</property>
Spring 2.5.6 引入 packagesToScan 屬性(屬於 AnnotationSessionFactoryBean 及其子類),自動掃描指定包下所有帶 @Entity/@Embeddable/@MappedSuperclass 註解的類,實現零配置映射註冊。
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="namingStrategy">
<bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
</value>
</property>
<!-- 核心配置:自動掃描實體類 -->
<property name="packagesToScan">
<list>
<value>com.pplus.*</value>
<!-- 注意:寫成 com.pplus.model.* 可能掃描不到,見下文避坑指南 -->
</list>
</property>
</bean>
| 模式 | 含義 | 示例 |
|---|---|---|
| 精確包名 | 僅掃描該包(不含子包) | com.pplus.model |
| 通配符 * | 掃描該包及所有子包 | com.pplus.* 掃描 model、dao、service 等所有子包 |
| 多包掃描 | 配置多個值,取並集 | <list><value>com.a.*</value><value>com.b.entity</value></list> |
ClassPathScanningCandidateComponentProvider,某些類加載器(如 JBoss 模塊、OSGi)不支持通配符遞歸target/classes/com/pplus/model/ 下@Entity、@Embeddable 或 @MappedSuperclass<property name="packagesToScan">
<list>
<value>com.pplus.*</value>
</list>
</property>
<!-- 配合 hibernate 排除 -->
<property name="hibernateProperties">
<value>
hibernate.ejb.entitymanager_factory_name=...
hibernate.archive.autodetection=class, hbm
</value>
</property>
# application.yml (Spring Boot 2.x/3.x)
spring:
jpa:
packages-to-scan: com.pplus.* # 自動配置 LocalContainerEntityManagerFactoryBean
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
Spring Boot 內部同樣使用 packagesToScan,但封裝在 LocalContainerEntityManagerFactoryBean 中,配置更簡潔。
@Configuration
@EnableJpaRepositories(basePackages = "com.pplus.dao.db1",
entityManagerFactoryRef = "db1EntityManagerFactory")
public class Db1Config {
@Bean
public LocalContainerEntityManagerFactoryBean db1EntityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(db1DataSource());
emf.setPackagesToScan("com.pplus.model.db1"); // 僅掃描 db1 相關實體
emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return emf;
}
}
AnnotationSessionFactoryBean.afterPropertiesSet()
│
▼
Configuration.class.getPackagesToScan() → String[] packages
│
▼
ClassPathScanningCandidateComponentProvider
│
├── 構建掃描器 (excludeFilters: 排除非註解類)
│
├── 掃描路徑: packagePath = "com/pplus/**/*.class"
│
├── 讀取 .class 文件字節碼 (ASM 庫,不加載類)
│
├── 檢查是否有 @Entity/@Embeddable/@MappedSuperclass
│
└── 收集類名 → Configuration.addAnnotatedClass(className)
│
▼
SessionFactoryBuilder.buildSessionFactory() ← 註冊所有發現的實體
| 因素 | 影響 | 優化策略 |
|---|---|---|
| 掃描包範圍過大 | 啟動讀取成千上萬 .class 文件,IO 開銷大 | 縮小包範圍;排除測試代碼包 |
| 類路徑包含大量依賴 jar | 掃描器需遍歷所有 jar 判斷包前綴 | 使用 excludeFilters 排除第三方包 |
| ASM 字節碼解析 | CPU 開銷,但遠小於類加載 | 無需優化,極快 |
@Entity 註解?packagesToScan 模式匹配?SessionFactoryBean 實現類?(AnnotationSessionFactoryBean 或 LocalSessionFactoryBean)log4j.logger.org.springframework.orm.hibernate3=DEBUGpackagesToScan 是 Spring 整合 Hibernate 的里程碑式特性,徹底消除了手動維護映射列表的痛苦。核心要點:
com.yourcompany.*spring.jpa.packages-to-scan掌握這一特性,能讓你的持久層配置更乾淨、更彈性、更易維護。