以下是一个 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
<?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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://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
)
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
)
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 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public 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
)
java
package com.example.service;
import com.example.model.User;
public interface UserService {
User getUserById(int id);
}
实现类 (UserServiceImpl.java
)
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 {
@Autowired
private UserDao userDao;
@Override
public User getUserById(int id) {
return userDao.findById(id);
}
}
5. Controller 层(注解驱动)
类 (UserController.java
)
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 {
@Autowired
private UserService userService;
@GetMapping("/users/{id}")
public User getUser(@PathVariable int id) {
return userService.getUserById(id);
}
}
6. 模型类 (User.java
)
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
)
properties
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.username=root
jdbc.password=secret
8. 启动应用
主类 (Application.java
)
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");
// 通过组件扫描自动发现 UserController
UserController 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 项目的推荐实践。