<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--开启Spring的注解--> <context:annotation-config/> <!--Spring的注解扫描包路径--> <context:component-scan base-package="com.example"/> <!--加载数据源连接池--> <bean name="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1/apsfc?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!--创建SqlSessionFactory对象--> <bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--注入数据源连接池--> <property name="dataSource" ref="druidDataSource"/> <!--注入Mybatis的主配置文件--> <property name="configLocation" value="classpath:sqlMapConfig.xml"/> <!--配置DAO的映射文件扫描路径--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--加载DAO接口扫描--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--将SqlSessionFactory对象进行注入--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--配置DAO接口的扫描基础路径--> <property name="basePackage" value="com.example.meal_ordering_system.dao.**"/> </bean> <!--加载事务管理器--> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--加载数据源连接池--> <property name="dataSource" ref="druidDataSource"/> </bean> <!--配置事务增强通知--> <!--transaction-manager加载指定的事务管理器--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--事务规则列表--> <tx:attributes> <!--propagation定义动作的规则--> <!--REQUIRED阻断操作--> <!--NOT_SUPPORTED非阻断操作--> <!--对新增数据操作的规则定义--> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <!--对修改数据操作的规则定义--> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="edit*" propagation="REQUIRED"/> <!--对删除数据操作的规则定义--> <tx:method name="delete*" propagation="REQUIRED"/> <!--对查询数据操作的规则定义--> <tx:method name="get*" propagation="NOT_SUPPORTED"/> <tx:method name="select*" propagation="NOT_SUPPORTED"/> <tx:method name="query*" propagation="NOT_SUPPORTED"/> </tx:attributes> </tx:advice> <!--托管通知工具类--> <bean name="advice" class="com.example.meal_ordering_system.util.AdviceUtil"/> <!--切面的配置--> <aop:config> <!--切面定义在Service层--> <aop:pointcut id="pointCut" expression="execution(* com.example.meal_ordering_system.service..*(..))"/> <!--将事务增强通知与切面进行绑定--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/> <!--切面织入--> <aop:aspect ref="advice"> <aop:before method="before" pointcut-ref="pointCut"/> <aop:after method="after" pointcut-ref="pointCut"/> <aop:around method="around" pointcut-ref="pointCut"/> <aop:after-throwing method="exception" pointcut-ref="pointCut"/> </aop:aspect> </aop:config> </beans>
时间: 2025-06-19 12:06:10 浏览: 6
### Spring框架事务管理、数据源配置及AOP切面具体实现
#### 一、Spring事务管理的实现
在Spring应用中,可以通过`@EnableTransactionManagement`注解启用事务支持,并通过声明式事务管理简化复杂的事务操作。以下是基于注解方式的事务管理示例:
```java
@Configuration
@EnableTransactionManagement // 启用事务管理
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource); // 配置事务管理器
}
}
```
在此基础上,在服务层方法上添加`@Transactional`注解即可开启事务[^1]。
---
#### 二、多数据源切换的实现
为了实现多数据源切换,可以借助AOP切面技术完成动态数据源的选择。以下是具体的实现步骤和代码示例:
##### 1. 定义数据源切换注解
创建一个自定义注解`@DataSourceSwitch`,用于标记需要切换的数据源名称。
```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceSwitch {
String value() default "master"; // 默认为主库
}
```
##### 2. 动态数据源路由逻辑
编写一个抽象类`AbstractRoutingDataSource`,负责根据上下文决定当前使用的数据源。
```java
public abstract class AbstractRoutingDataSource extends AbstractDataSource {
private final Map<Object, Object> targetDataSources;
private final Object defaultTargetDataSource;
protected AbstractRoutingDataSource(Map<Object, Object> targetDataSources, Object defaultTargetDataSource) {
this.targetDataSources = Collections.unmodifiableMap(new HashMap<>(targetDataSources));
this.defaultTargetDataSource = defaultTargetDataSource;
}
@Override
public Connection getConnection() throws SQLException {
return determineCurrentLookupKey().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineCurrentLookupKey().getConnection(username, password);
}
protected Object determineCurrentLookupKey() {
String lookupKey = DynamicDataSourceContextHolder.getDataSourceType(); // 获取线程绑定的数据源key
if (lookupKey == null || "".equals(lookupKey)) {
return defaultTargetDataSource; // 返回默认数据源
}
return targetDataSources.get(lookupKey);
}
}
```
##### 3. 创建动态数据源持有者
使用ThreadLocal保存当前线程的数据源类型。
```java
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String type) {
contextHolder.set(type);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
```
##### 4. 编写AOP切面逻辑
通过AOP拦截带有`@DataSourceSwitch`注解的方法并设置对应的数据源。
```java
@Aspect
@Component
public class DataSourceSwitchAspect {
@Around("@annotation(dataSourceSwitch)")
public Object around(ProceedingJoinPoint joinPoint, DataSourceSwitch dataSourceSwitch) throws Throwable {
String originalDataSource = DynamicDataSourceContextHolder.getDataSourceType(); // 记录原始数据源
try {
DynamicDataSourceContextHolder.setDataSourceType(dataSourceSwitch.value()); // 设置目标数据源
return joinPoint.proceed();
} finally {
DynamicDataSourceContextHolder.setDataSourceType(originalDataSource); // 恢复原始数据源
}
}
}
```
以上代码展示了如何利用AOP切面实现动态数据源切换的功能[^4]。
---
#### 三、AOP切面实现详解
Spring AOP的核心在于通知(Advice)、切入点(Pointcut)和连接点(Join Point)。下面是一个简单的日志记录切面示例:
```java
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))") // 切入点表达式匹配service包下的所有方法
public void logBefore(JoinPoint joinPoint) {
System.out.println("Method Name: " + joinPoint.getSignature().getName());
System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("Return Value: " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void logAfterThrowing(Exception ex) {
System.out.println("Exception Occurred: " + ex.getMessage());
}
}
```
此示例展示了如何通过AOP切面对指定方法进行前置、返回值和异常的日志记录[^5]。
---
#### 四、总结
上述代码分别演示了Spring框架下事务管理、多数据源切换以及AOP切面的具体实现方式。这些功能共同构成了Spring强大的企业级解决方案体系。
阅读全文
相关推荐










<?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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.itheihei" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:annotation-driven/> </beans><?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.itheihei"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>@Controller public class AccountController { @Autowired AccountService accountService; @RequestMapping("findAllAccounts") public String findAllAccounts() { System.out.println("方法成功执行"); return "list"; } } <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首页</title> </head> <body> 查看所有用户信息 </body> </html><?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> contextConfigLocation classpath:spring-mvc.xml </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>为什么会404








