以下是一個 Spring XML + 注解的混合配置示例,結合了 XML 的基礎設施配置(如數據源、事務管理器)和注解的便捷性(如依賴注入、事務聲明)。所有業務層代碼通過注解簡化,但核心配置仍通過 XML 管理。
1. 項目結構
src/main/java
├── com.example.dao
│ └── UserDao.java # DAO 接口
│ └── impl
│ └── UserDaoImpl.java # DAO 實現類(注解驅動)
├── com.example.service
│ ├── UserService.java # Service 接口
│ └── impl
│ └── UserServiceImpl.java # Service 實現類(@Service + @Transactional)
└── com.example.controller└── UserController.java # Controller 類(@Controller)
resources
├── applicationContext.xml # Spring 主配置文件
└── db.properties # 數據庫配置文件
2. XML 配置 (applicationContext.xml
)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 1. 啟用組件掃描(自動發現 @Component, @Service, @Repository, @Controller) --><context:component-scan base-package="com.example"/><!-- 2. 數據源配置(通過 properties 文件注入) --><context:property-placeholder location="classpath:db.properties"/><bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"><property name="jdbcUrl" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!-- 3. JdbcTemplate 配置(用于 DAO 層) --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean><!-- 4. 事務管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 5. 啟用注解驅動的事務管理(@Transactional) --><tx:annotation-driven transaction-manager="transactionManager"/></beans>
3. DAO 層(注解驅動)
接口 (UserDao.java
)
package com.example.dao;import com.example.model.User;
import org.springframework.stereotype.Repository;@Repository // 標記為 DAO 組件,自動被組件掃描發現
public interface UserDao {User findById(int id);
}
實現類 (UserDaoImpl.java
)
package com.example.dao.impl;import com.example.dao.UserDao;
import com.example.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository // 替代 XML 中的 <bean> 定義
public class UserDaoImpl implements UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic User findById(int id) {String sql = "SELECT * FROM users WHERE id = ?";return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) ->new User(rs.getInt("id"), rs.getString("name")));}
}
4. Service 層(注解驅動 + 事務)
接口 (UserService.java
)
package com.example.service;import com.example.model.User;public interface UserService {User getUserById(int id);
}
實現類 (UserServiceImpl.java
)
package com.example.service.impl;import com.example.dao.UserDao;
import com.example.model.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; // 聲明事務@Service // 替代 XML 中的 <bean> 定義
@Transactional // 默認事務配置(REQUIRED 傳播行為)
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic User getUserById(int id) {return userDao.findById(id);}
}
5. Controller 層(注解驅動)
類 (UserController.java
)
package com.example.controller;import com.example.model.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController // 替代 XML 中的 <bean> 定義
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/users/{id}")public User getUser(@PathVariable int id) {return userService.getUserById(id);}
}
6. 模型類 (User.java
)
package com.example.model;public class User {private int id;private String name;public User(int id, String name) {this.id = id;this.name = name;}// Getter 和 Setter 省略
}
7. 數據庫配置 (db.properties
)
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.username=root
jdbc.password=secret
8. 啟動應用
主類 (Application.java
)
package com.example;import com.example.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Application {public static void main(String[] args) {// 初始化 Spring 上下文(僅加載 XML 配置)ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 通過組件掃描自動發現 UserControllerUserController userController = context.getBean(UserController.class);User user = userController.getUser(1);System.out.println("User: " + user.getName());// 關閉上下文context.close();}
}
關鍵點說明
-
混合配置的優勢
- XML:管理數據源、事務管理器等基礎設施。
- 注解:簡化業務層的依賴注入(
@Autowired
)和事務聲明(@Transactional
)。
-
組件掃描
<context:component-scan>
自動發現@Component
、@Service
、@Repository
、@Controller
注解的類,無需 XML 定義 Bean。
-
事務管理
<tx:annotation-driven>
啟用@Transactional
注解,替代 XML 中的 AOP 事務配置。
-
依賴注入
- 所有依賴通過
@Autowired
注入,無需 XML 中的<property>
標簽。
- 所有依賴通過
常見問題排查
-
Bean 未找到
- 檢查
<context:component-scan>
的包路徑是否包含所有組件。 - 確保類上有正確的注解(如
@Service
、@Repository
)。
- 檢查
-
事務不生效
- 檢查
@Transactional
是否添加到public
方法。 - 確保
<tx:annotation-driven>
已配置且事務管理器正確。
- 檢查
-
數據庫連接失敗
- 檢查
db.properties
中的 URL、用戶名和密碼。 - 確保數據庫驅動已添加到依賴(如 MySQL 的
mysql-connector-java
)。
- 檢查
通過這種混合模式,既能享受 XML 的集中式基礎設施配置,又能利用注解簡化業務層代碼,是傳統 Spring 項目的推薦實踐。