Spring自定义@Aspect与TransactionInterceptor先后执行问题

本文探讨了在Spring中自定义@Aspect与TransactionInterceptor的执行顺序问题。通过调整@Aspect的order属性为10和TransactionInterceptor的Advisor order属性为5,实现了在事务结束前执行自定义分析并保存数据到数据库的操作。由于DefaultPointcutAdvisor的默认order值,需明确设置在Advisor中以控制执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义@Aspect分析返回结果,并保存到数据库中,所以希望在事务结束前处理。
对应方法:
1.自定义@Aspect中增加order,数值定为10。
2.事务的@Aspect中,返回值Advisor设置order为5。
事务拦截的类中直接设置order不起作用,因为@Configuration+@Bean与xml同样作用,要写在新归Advisor处,才相当于

<aop:advisor advice-ref="txAdvice" pointcut-ref="appService" order="2"/>

中设置的order。

原因:
DefaultPointcutAdvisor类继承了Ordered类,Ordered类里默认的order为Integer.MAX_VALUE,这样他总是最里层执行,设置为5之后,比5大的都可以在事务里了。

代码如下:


import java.util.Collections;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 事务管理设定类
 *
 * @author
 */
@Aspect
@Configuration
public class TxAdviceConfig {

	private static final String TX_METHOD_NAME = "*";
	private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.example.application..*Service.*(..))"
			+ " && @within(org.springframework.stereotype.Service)"
			+ " && !@within(org.springframework.transaction.annotation.Transactional)"
			+ " && !@annotation(org.springframework.transaction.annotation.Transactional)";

	@Autowired
	private PlatformTransactionManager transactionManager;

	@Value("${smart-config.service.timeout:#{null}}")
	private Integer txMethodTimeout;

	/**
	 * tx:advice设定
	 *
	 * @return TransactionInterceptor
	 */
	@Bean
	public TransactionInterceptor txAdvice() {
		MatchAlwaysTransactionAttributeSource source = new MatchAlwaysTransactionAttributeSource();
		RuleBasedTransactionAttribute transactionAttribute = new RuleBasedTransactionAttribute();
		transactionAttribute.setName(TX_METHOD_NAME);
		transactionAttribute.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
		if (null != txMethodTimeout) {
			transactionAttribute.setTimeout(txMethodTimeout);
		}
		source.setTransactionAttribute(transactionAttribute);
		TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
		return txAdvice;
	}

	/**
	 * aop:advisor设定
	 *
	 * @return Advisor
	 */
	@Bean
	public Advisor txAdviceAdvisor() {
		AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
		pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, txAdvice());
		advisor.setOrder(5);
		return advisor;
	}

}

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.example.query.common.CommonReadModel;
import com.example.application.service.CommonService;

/**
  * 对所有service层方法进行拦截。
  *
  * @author
  *
  */
@Component
@Aspect
public class ServiceAspect implements Ordered {

	private static final Log LOG = LogFactory.getLog(ServiceAspect.class);

	@Autowired
	private CommonService service;

	/**
	 * service执行前的拦截,可以用来取request情报
	 *
	 * @param joinPoint JoinPoint
	 */
	@Before(value = "servicePointCut()")
	public void doBefore(JoinPoint joinPoint) {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		LOG.info("URI:" + request.getRequestURI());
	}

	@Pointcut("execution(* dfv.dynamic.smart.application..*Service.*(..))"
			+ " && @within(org.springframework.stereotype.Service)"
			+ " && !@within(org.springframework.transaction.annotation.Transactional)"
			+ " && !@annotation(org.springframework.transaction.annotation.Transactional)")
	private void servicePointCut() {
	}

	/**
	 * service里的方法执行完,事务未关闭前执行
	 *
	 * @param ret service执行完的返回值
	 */
	@AfterReturning(returning = "ret", pointcut = "servicePointCut()")
	public void doAfterReturning(Object ret) {
		try {
			if (ret instanceof CommonReadModel) {
				CommonReadModel commonBean= (CommonReadModel) ret;
				// 保存到数据库的处理
				service.insertLogIntoTable(commonBean.getReadModel());
				LOG.info("执行成功!");
			}

		} catch (Throwable e) {
			// 可以抛异常
		}
	}

	@Override
	public int getOrder() {
		return 10;
	}
}
import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * service返回值的bean要保存数据库就要继承这个bean
 *
 */
public interface CommonReadModel{

	/**
	 * 取得用户操作返回值
	 *
	 */
	@JsonIgnore
	CommonInformation getReadModel();
}

import java.util.List;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import com.example.query.common.CommonReadModel;
import com.example.query.common.CommonInformation;

/**
 * 做某事的返回值bean
 *
 */
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public final class XXXReadModel implements CommonReadModel {

	private final List<XXX> xxx;

	/**
	 *
	 */
	public XXXReadModel(List<XXX> xxx) {
		this.xxx = List.copyOf(xxx);
	}

	public List<XXX> getXXX() {
		return xxx;
	}
	@Override
	public CommonInformation getReadModel() {
		return new CommonInformation("111");
	}
}

CommonInformation 为自定义的要保存到数据库中的信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值