首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring + SpringMVC + Hibernate 純 JavaConfig 配置指南:告別 XML 的優雅實踐

     編輯:Java 綜合教學

從 XML 到 JavaConfig:類型安全、重構友好的配置革命

Spring 3.0 將 Spring JavaConfig 併入核心,開啟了「純 Java 配置」時代。相比 XML,JavaConfig 兼具解耦性與編譯期類型檢查,重構時 IDE 可直接跳轉、重命名,杜絕拼寫錯誤。本文完整演示如何用 JavaConfig 搭建 SSH(Spring + SpringMVC + Hibernate)棧。

一、專案結構

src/main/java
├── config
│   ├── WebInitializer.java      // Servlet 3.0+ 啟動入口
│   ├── WebConfig.java           // SpringMVC 配置(Web 層)
│   ├── RootConfig.java          // 根容器配置(Service/DAO/數據源)
│   └── HibernateConfig.java     // Hibernate 專用配置
├── entity
│   └── User.java                // JPA 實體
├── service
│   └── UserService.java
├── dao
│   └── UserDao.java
└── test
    └── ServiceTest.java         // 整合測試

專案目錄結構

二、啟動入口:WebInitializer 替代 web.xml

@Order(1)
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 根容器:Service、DAO、DataSource、Hibernate
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { RootConfig.class };
    }

    // Web 容器:Controller、ViewResolver、HandlerMapping
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebConfig.class };
    }

    // DispatcherServlet 映射路徑
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    // 可選:註冊 Filter(如 HiddenHttpMethodFilter 支持 PUT/DELETE)
    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new HiddenHttpMethodFilter() };
    }
}

原理:實現 WebApplicationInitializer,Servlet 3.0 容器啟動時自動發現並調用 onStartup(),完成兩個容器創建與 DispatcherServlet 註冊。

初始化類繼承體系

三、雙容器架構職責劃分

容器配置類掃描包典型 Bean
根容器
(ContextLoaderListener)
RootConfigscau.zzf 排除 .webService、DAO、DataSource、SessionFactory、TransactionManager
Web 容器
(DispatcherServlet)
WebConfigscau.zzf.webController、ViewResolver、Interceptor、Converter
// RootConfig.java - 排除 Web 層,避免重複掃描
@Configuration
@Import(HibernateConfig.class)
@ComponentScan(basePackages = "scau.zzf", excludeFilters = @ComponentScan.Filter(
    type = FilterType.CUSTOM, value = RootConfig.WebPackage.class))
public class RootConfig {
    public static class WebPackage extends RegexPatternTypeFilter {
        public WebPackage() { super(Pattern.compile("scau\\.zzf\\.web")); }
    }
}

四、Web 層配置:WebConfig

@Configuration
@EnableWebMvc                    // 等同 <mvc:annotation-driven>
@ComponentScan("scau.zzf.web")   // 掃描 Controller
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    // 靜態資源處理:轉發給容器默認 Servlet
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

五、Hibernate 整合:HibernateConfig

@Configuration
@PropertySource("classpath:ds/ds-jdbc.properties")  // 載入外部屬性文件
public class HibernateConfig {

    @Value("${jdbc.driverClassName}") private String driver;
    @Value("${jdbc.url}") private String url;
    @Value("${jdbc.username}") private String user;
    @Value("${jdbc.password}") private String pass;

    @Bean
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(user);
        ds.setPassword(pass);
        return ds;
    }

    @Bean
    public SessionFactory sessionFactory() throws IOException {
        LocalSessionFactoryBean fb = new LocalSessionFactoryBean();
        fb.setDataSource(dataSource());
        fb.setPackagesToScan("scau.zzf.entity");  // 自動掃描 @Entity
        Properties props = new Properties();
        props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        fb.setHibernateProperties(props);
        fb.afterPropertiesSet();  // 必須調用,初始化 SessionFactory
        return fb.getObject();
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer(); // 解析 ${...}
    }
}

六、實體與測試

// User.java - JPA 註解映射
@Entity
@Table(catalog = "hibernate", name = "users")
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column private String username;
    @Column private String password;
    // ... getter/setter
}

// ServiceTest.java - 整合測試
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebConfig.class, RootConfig.class})
@WebAppConfiguration
public class ServiceTest {
    @Autowired private UserService userService;

    @Test
    public void testFindUser() {
        User u = userService.findUser(1);
        System.out.println(u.getUsername());
    }
}

七、關鍵優勢總結

  1. 類型安全:重構類名/方法名,編譯器即時報錯
  2. IDE 友好:跳轉定義、查找引用、重命名重構全支援
  3. 條件裝配:@Profile、@Conditional 靈活控制 Bean 載入
  4. 模組化組合:@Import 輕鬆組裝配置類,替代 <import>
  5. 零 XML:專案中不再出現任何 .xml 配置文件

八、避坑指南

  • LocalSessionFactoryBean.afterPropertiesSet() 必須顯式調用,否則 getObject() 返回 null
  • 測試類必須標註 @WebAppConfiguration,否則 WebApplicationContext 無法加載
  • 靜態資源映射 configurer.enable() 別漏,否則 CSS/JS 404
  • 屬性文件路徑 classpath:ds/ds-jdbc.properties 需確保在 resources 目錄下

「JavaConfig 不是為了炫技,而是為了讓配置像業務代碼一樣可維護、可重構、可測試。」

下一步嘗試:引入 @EnableTransactionManagement 開啟註解式事務、整合 HikariCP 替換 DBCP、配置二級緩存與查詢緩存。完整代碼已上傳 GitHub,歡迎 Star!⭐

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved