Spring宣言トランザクションと@Aspectのブロック順序の問題の解決
2723 ワード
AbstractRoutingDataSourceを使用してマルチデータソースを構成する場合、@aspectを使用して構成されたDataSourceSwitchAspectは常に宣言トランザクションの後に実行され、Orderを構成することは依然としてできません.調査の結果、両者のaopエージェント方式が一致していないためです.
Spring内部では、BeanPostProcessor(「spring攻略」という本では、ポストプロセッサと訳されています)によってエージェントの自動作成が完了します.マッチングルールによって大きく3つのカテゴリに分けられる:1、マッチングBeanの名前によってマッチングしたBeanのエージェントが自動的に作成され、実装クラスBeanNameAutoProxyCreator 2、実装クラスBeanのAspectJ注記に基づいてエージェントが自動的に作成され、実装クラスAnnotationAwareAspectJAutoProxyCreator 3、Advisorのマッチングメカニズムに基づいてエージェントが自動的に作成され、コンテナ内のすべてのAdvisorがスキャンされ、一致するBeanに自動的に適用されます.
ここで@Aspectで宣言されたaopは、A n o t i o n A w a r e A w e A s p e ctJAutoProxyCreatorによってエージェントされ、プロジェクト内の宣言トランザクションはBeanNameAutoProxyCreatorによってエージェントされています.デバッグにより、BeanNameAutoProxyCreatorのブロック優先度は、次のようになります.
DataSourceSwitchAspect
DataSourceConfig
ソリューション:DataSourceSwitchAspectのaop方式をBeanName AutoProxyCreatorに変更するか、トランザクションaop方式をN o t i o t ionAwareAspectJAutoProxyCreatorに変更するか、注釈によって実現されるデータソースによってaopを切り替えるため、後者のソリューションを選択しました.
DataSourceConfig
Spring内部では、BeanPostProcessor(「spring攻略」という本では、ポストプロセッサと訳されています)によってエージェントの自動作成が完了します.マッチングルールによって大きく3つのカテゴリに分けられる:1、マッチングBeanの名前によってマッチングしたBeanのエージェントが自動的に作成され、実装クラスBeanNameAutoProxyCreator 2、実装クラスBeanのAspectJ注記に基づいてエージェントが自動的に作成され、実装クラスAnnotationAwareAspectJAutoProxyCreator 3、Advisorのマッチングメカニズムに基づいてエージェントが自動的に作成され、コンテナ内のすべてのAdvisorがスキャンされ、一致するBeanに自動的に適用されます.
ここで@Aspectで宣言されたaopは、A n o t i o n A w a r e A w e A s p e ctJAutoProxyCreatorによってエージェントされ、プロジェクト内の宣言トランザクションはBeanNameAutoProxyCreatorによってエージェントされています.デバッグにより、BeanNameAutoProxyCreatorのブロック優先度は、次のようになります.
DataSourceSwitchAspect
/**
*
* @author Matchstick
*/
@Aspect
@Order(1) // transaction
@Component
public class DataSourceSwitchAspect
{
private Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.etu.multidatasource.test.datasource.DataSourceId)")
public void pointcut(){}
@Before("@annotation(dataSourceId)")
public void switchDataSource(JoinPoint point, DataSourceId dataSourceId)
{
String dsId = dataSourceId.value();
MultiDataSourceContextHolder.setDataSourceId(dsId);
logger.debug("switch datasource -> {}", dsId);
}
@After("@annotation(dataSourceId)")
public void restoreDataSource(JoinPoint point, DataSourceId dataSourceId)
{
MultiDataSourceContextHolder.removeDataSourceId();
logger.debug("restore datasource -> {}", MultiDataSourceContextHolder.getDefaultDataSourceId());
}
}
DataSourceConfig
@Bean
public BeanNameAutoProxyCreator txProxy()
{
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
creator.setInterceptorNames("txAdvice");
creator.setBeanNames("*Service", "*ServiceImpl");
creator.setProxyTargetClass(true);
creator.setOrder(2);
return creator;
}
ソリューション:DataSourceSwitchAspectのaop方式をBeanName AutoProxyCreatorに変更するか、トランザクションaop方式をN o t i o t ionAwareAspectJAutoProxyCreatorに変更するか、注釈によって実現されるデータソースによってaopを切り替えるため、後者のソリューションを選択しました.
DataSourceConfig
@Bean
public AnnotationAwareAspectJAutoProxyCreator txProxy()
{
/*
* AspectJ AutoProxy, DataSourceSwitchAspect aop , order
*/
AnnotationAwareAspectJAutoProxyCreator c = new AnnotationAwareAspectJAutoProxyCreator();
c.setInterceptorNames("txAdvice");
c.setIncludePatterns(Arrays.asList("execution (public com.etu..*Service(..))"));
c.setProxyTargetClass(true);
c.setOrder(2);
return c;
}