ShardingSphere之Hint强制路由自定义注解
1、引入依赖
<!--AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<!--context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!--切面依赖包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>compile</scope>
</dependency>
<!--sharding分库分表路由-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-core-route</artifactId>
<version>4.0.0-RC1</version>
</dependency>
2、定义注解
@Retention(RetentionPolicy.RUNTIME) // 持有策略,将由编译器记录在类文件中,并且在运行时由VM保留,可以通过反射读取它们
@Target(ElementType.METHOD) // 作用域为方法,即该注解只能再方法上使用
public @interface ShardingHint {
/**
* 设置的值
*
* @return value
*/
String value() default "";
/**
* 分片类型
*
* @return ShardingTypeEnum
*/
ShardingTypeEnum type() default ShardingTypeEnum.DATABASE_ONLY;
}
3、定义切面程序
import org.apache.shardingsphere.api.hint.HintManager;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* <p> 强制路由 </p>
*
* @author lijinghao
* @version : BaseAdvice.java, v 0.1 2019年07月22日 下午8:20:58 lijinghao Exp $
*/
@Aspect
@Component
public class ShardingHintAdvice {
private static final Logger logger = LoggerFactory.getLogger(ShardingHintAdvice.class);
/**
* 设置切点
*/
@Pointcut("@annotation(com.u51.yacolpay.annotation.ShardingHint)")
public void hintRoute() {
}
/**
* 设置强制路由
*
* @param joinPoint 切点
* @return 执行结果
* @throws Throwable 异常
*/
@Around("hintRoute()")
public Object setHintRoute(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取注解所在的方法
Method method = getCurrentMethod(joinPoint);
// 获取要处理的注解
ShardingHint shardingHint = method.getAnnotation(ShardingHint.class);
// 获取注解里的值
String value = shardingHint.value();
ShardingTypeEnum type = shardingHint.type();
if (logger.isDebugEnabled()) {
logger.debug("强制路由: type:{}, value:{}", type, value);
}
// 处理程序
Object object;
switch (type) {
case DATABASE_ONLY:
try (HintManager hintManager = HintManager.getInstance()) {
hintManager.setDatabaseShardingValue(value);
// 调用程序
object = joinPoint.proceed();
}
break;
case MASTER_ONLY:
case DATABASE_TABLE:
default:
throw new RuntimeException("尚不支持的注解式Hint路由方式");
}
return object;
}
@Before("hintRoute()")
public void beforeProcess() {
// 调用前操作
}
@Before("hintRoute()")
public void afterProcess() {
// 调用结束后操作
}
@AfterThrowing(pointcut = "hintRoute()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
// 可以用来处理异常
}
/**
* 获取当前方法
*
* @param pjp
* @return
* @throws Throwable
*/
private Method getCurrentMethod(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
if (!(signature instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
MethodSignature methodSignature = (MethodSignature) signature;
return pjp.getTarget()
.getClass()
.getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
}
4、配置
4.1 开启AOP配置
4.2 创建Spring Bean
- 可以通过自动扫描,
ShardingHintAdvice
处理类上需要有@Component
注解;
<!--自动扫描配置-->
<context:component-scan base-package="com.xxx.example"/>
- 可以通Spring的bean标签配置;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shardingDatabaseHintAdvice" class="com.u51.yacolpay.annotation.ShardingDatabaseHintAdvice"/>
<bean id="hintStrategyAlgorithm" class="com.u51.yacolpay.hint.HintStrategyAlgorithm"/>
</beans>
5、测试
因为AOP是基于动态代理来实现的,所以调用的时候需要通过接口调用.
启动类:
public class SpringNamespaceMybatisExample {
private static final String CONFIG_FILE = "META-INF/application-sharding-databases.xml";
public static void main(final String[] args) {
try (ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(CONFIG_FILE)) {
SpringPojoService service = applicationContext.getBean(SpringPojoService.class);
// 通过接口调用时, 配置的AOP Hint注解有效
service.printData();
}
}
}
服务类:
public interface SpringPojoService {
void printData();
}
实现类:
@Service
public class SpringPojoServiceImpl implements SpringPojoService {
@Override
// @ShardingHint(value = "test_0", type = ShardingTypeEnum.DATABASE_ONLY)
@ShardingHint
public void printData() {
System.out.println("---------------------------- Print Order Data -----------------------");
for (Object each : orderRepository.selectAll()) {
System.out.println(each);
}
}
}
测试:
在ShardingHintAdvice
中进行断点,看是否进入了。
这里分库的结果是设置了Hint类型,会跳过SQL解析,直接进入Hint算法,完成路由。
其他
这关于自定义注解仅做了实现, 并未做讲解,网上已经有很多文章了。
参考:
Spring 官方文档
springAOP自定义注解讲解