001/* 002 * Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.mybatisflex.spring.datasource; 018 019import com.mybatisflex.annotation.UseDataSource; 020import com.mybatisflex.core.datasource.DataSourceKey; 021import com.mybatisflex.core.util.StringUtil; 022import com.mybatisflex.processor.util.StrUtil; 023import org.aopalliance.intercept.MethodInterceptor; 024import org.aopalliance.intercept.MethodInvocation; 025import org.springframework.core.MethodClassKey; 026 027import java.lang.reflect.Method; 028import java.util.Map; 029import java.util.concurrent.ConcurrentHashMap; 030 031/** 032 * 多数据源切换拦截器。 033 * 034 * @author 王帅 035 * @author barql 036 * @author michael 037 * @since 2023-06-25 038 */ 039public class DataSourceInterceptor implements MethodInterceptor { 040 041 /** 042 * 缓存方法对应的数据源。 043 */ 044 private final Map<Object, String> dsCache = new ConcurrentHashMap<>(); 045 046 @Override 047 public Object invoke(MethodInvocation invocation) throws Throwable { 048 String dsKey = getDataSourceKey(invocation.getThis(), invocation.getMethod(), invocation.getArguments()); 049 if (StringUtil.noText(dsKey)) { 050 return invocation.proceed(); 051 } 052 try { 053 DataSourceKey.use(dsKey); 054 return invocation.proceed(); 055 } finally { 056 DataSourceKey.clear(); 057 } 058 } 059 060 private String getDataSourceKey(Object target, Method method, Object[] arguments) { 061 Object cacheKey = new MethodClassKey(method, target.getClass()); 062 String dsKey = this.dsCache.get(cacheKey); 063 if (dsKey == null) { 064 dsKey = determineDataSourceKey(method, target.getClass()); 065 // 对数据源取值进行动态取值处理 066 if (!StrUtil.isBlank(dsKey)) { 067 dsKey = DataSourceKey.processDataSourceKey(dsKey, target, method, arguments); 068 } 069 this.dsCache.put(cacheKey, dsKey); 070 } 071 return dsKey; 072 } 073 074 private String determineDataSourceKey(Method method, Class<?> targetClass) { 075 // 方法上定义有 UseDataSource 注解 076 UseDataSource annotation = method.getAnnotation(UseDataSource.class); 077 if (annotation != null) { 078 return annotation.value(); 079 } 080 // 类上定义有 UseDataSource 注解 081 annotation = targetClass.getAnnotation(UseDataSource.class); 082 if (annotation != null) { 083 return annotation.value(); 084 } 085 // 接口上定义有 UseDataSource 注解 086 Class<?>[] interfaces = targetClass.getInterfaces(); 087 for (Class<?> anInterface : interfaces) { 088 annotation = anInterface.getAnnotation(UseDataSource.class); 089 if (annotation != null) { 090 return annotation.value(); 091 } 092 } 093 // 哪里都没有 UseDataSource 注解 094 return ""; 095 } 096 097}