Spring aop Aspect獲取註解在類的自定義註解裏面的參數

在Spring Boot + Mybatis 動態數據源基礎上,很多教程(文末附鏈接了)都是實現方法級別的切換,按照普遍教程都是這樣的

1.聲明一個自定義註解,並且帶參數的

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    
    /**
     * 數據源key值
     * @return
     */
    String value();
    
}

2.然後按照設置切點

@Before("@annotation(dataSource))")

3.再到實現上就是

@RestController
@RequestMapping("user")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;
    
    
    @DataSource(value="master")
    @PostMapping(value="/findAll")
    public Object findAll() {
        return sysUserService.findAll();
    }
    
    @DataSource(value="slave")
    @PostMapping(value="/findAll2")
    public Object findAll2() {
        return sysUserService.findAll();
    }

}

通過方法上的註解,來切換不同的數據源

但是我懶啊

需求就來了:::::

  • 我不想一個一個方法寫註解,大同小異參數又沒有什麼大變化,都是DataSource的key
  • 我想只能在類上面註解,實現整個類的數據源變化
  • 我還想有的方法可能不適用,我得有優先級,如果在方法上有註解話,優先使用方法上的

開搞:如何把數據源自定義註解放在類上,然後切點去掃描類,獲取切點類上面的自定義參數,來實現切換數據源

主要方向就是切點設置這邊啦直接貼出來

package com.wsh.demo.asp;

import com.wsh.demo.config.dynDataSource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author: wsh
 */
@Aspect
@Order(-1)  // 該切面應當先於 @Transactional 執行
@Component
public class DynamicDataSourceAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 切換數據源
     */
    @Around("execution(@com.wsh.demo.asp.DataSource * *(..))")
    public Object  aroundController(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取切入的 Method
        MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
        Method method = joinPointObject.getMethod();

        boolean flag = method.isAnnotationPresent(DataSource.class);
        if (flag) {
            DataSource dataSource = method.getAnnotation(DataSource.class);
            setDataSource(dataSource,method);
        } else {
            // 如果方法上沒有註解,則搜索類上是否有註解
            DataSource classDataSource = AnnotationUtils.findAnnotation(joinPointObject.getMethod().getDeclaringClass(), DataSource.class);
            if (classDataSource != null) {
                setDataSource(classDataSource,method);
            } else {
                DynamicDataSourceContextHolder.clearDataSourceKey();
                logger.info("沒有註解使用默認的");
            }
        }
        Object proceed = pjp.proceed();
        // 將數據源置爲默認數據源
        DynamicDataSourceContextHolder.clearDataSourceKey();
        return proceed;
    }

    private void setDataSource(DataSource dataSource,Method method ) {
        if (!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())) {
            logger.info("DataSource [{}] doesn't exist, use default DataSource [{}] " + dataSource.value());
        } else {
            // 切換數據源
            DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
            logger.info("Switch DataSource to [" + DynamicDataSourceContextHolder.getDataSourceKey() +
                    "] in Method [" + method.getName() + "]");
        }
    }

}

感謝下面的文章,一個是教程,一個是優化時候,從切點上獲取到靈光點 

Spring Boot + Mybatis 實現動態數據源

SpringAOP如何獲得執行方法的class上的註解信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章