Custom annotation - based on spring AOP

Keywords: Spring Database Apache Java

Hint forced routing custom annotation of ShardingSphere

1. Introduce dependency

<!--AOP-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
</dependency>
<!--context-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
</dependency>
<!--Faceted dependency package-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <scope>compile</scope>
</dependency>
<!--sharding Sub database and sub table routing-->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-core-route</artifactId>
    <version>4.0.0-RC1</version>
</dependency>

2. Definition notes

@Retention(RetentionPolicy.RUNTIME) // Holding policies, which are recorded by the compiler in the class file and kept by the VM at runtime, can be read by reflection
@Target(ElementType.METHOD) // Scope is method, that is, the annotation can only be used on method
public @interface ShardingHint {
	/**
     * Set value
     *
     * @return value
     */
    String value() default "";
    
	/**
     * Fragment type
     *
     * @return ShardingTypeEnum
     */
    ShardingTypeEnum type() default ShardingTypeEnum.DATABASE_ONLY;
}

3. Define the section procedure

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> Forced routing</p>
 *
 * @author lijinghao
 * @version : BaseAdvice.java, v 0.1 2019 July 22, 2008 8:20:58 PM$
 */
@Aspect
@Component
public class ShardingHintAdvice {
    private static final Logger logger = LoggerFactory.getLogger(ShardingHintAdvice.class);

    /**
     * Set tangent points
     */
    @Pointcut("@annotation(com.u51.yacolpay.annotation.ShardingHint)")
    public void hintRoute() {
    }

    /**
     * Set forced route
     *
     * @param joinPoint Tangent point
     * @return results of enforcement
     * @throws Throwable abnormal
     */
    @Around("hintRoute()")
    public Object setHintRoute(ProceedingJoinPoint joinPoint) throws Throwable {
        // How to get the annotation
        Method method = getCurrentMethod(joinPoint);

        // Get comments to process
        ShardingHint shardingHint = method.getAnnotation(ShardingHint.class);
        // Get the value in the annotation
        String value = shardingHint.value();
        ShardingTypeEnum type = shardingHint.type();

        if (logger.isDebugEnabled()) {
            logger.debug("Mandatory routing: type:{}, value:{}", type, value);
        }

        // processing program
        Object object;
        switch (type) {
            case DATABASE_ONLY:
                try (HintManager hintManager = HintManager.getInstance()) {
                    hintManager.setDatabaseShardingValue(value);

                    // Calling procedure
                    object = joinPoint.proceed();
                }
                break;
            case MASTER_ONLY:
            case DATABASE_TABLE:
            default:
                throw new RuntimeException("Annotation not yet supported Hint Routing mode");
        }
        return object;
    }

    @Before("hintRoute()")
    public void beforeProcess() {
        // Pre call action
    }

    @Before("hintRoute()")
    public void afterProcess() {
        // Operation after calling
    }

    @AfterThrowing(pointcut = "hintRoute()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        // Can be used to handle exceptions
    }

    /**
     * Get current method
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    private Method getCurrentMethod(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();
        if (!(signature instanceof MethodSignature)) {
            throw new IllegalArgumentException("This annotation can only be used for methods");
        }
        MethodSignature methodSignature = (MethodSignature) signature;

        return pjp.getTarget()
                .getClass()
                .getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }
}

4, configuration

4.1 enable AOP configuration

4.2 creating a Spring Bean

  • Through automatic scanning, the shardinghintavice processing class needs to have @ Component annotation;
 <!--Autoscan configuration-->
 <context:component-scan base-package="com.xxx.example"/>
  • It can be configured through the bean tag of Spring.
<?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, test

Because AOP is based on dynamic proxy, it needs to be called through interface.

Startup class:

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);
            // When called through an interface, the configured AOP Hint annotation is valid
            service.printData();
        }
    }
}

Service category:

public interface SpringPojoService {
    void printData();
}

Implementation class:

@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);
        }
    }
}

Test:
Break point in shardinghintavice to see if it is entered.

Here, the result of the sub database is that the Hint type is set, which will skip the SQL parsing and directly enter the Hint algorithm to complete the routing.

Other

This is only about the implementation of user-defined annotation, not to explain, there are many articles on the Internet.
Reference resources:
Official Spring documentation
Explanation of spring AOP custom annotation

Posted by nloding on Fri, 18 Oct 2019 12:32:40 -0700