基于spring的注解开发

420 阅读2分钟

注解的优点以及功能

  • 动态修改属性
  • 动态新增功能(不侵入原代码)
  • 动态改变执行逻辑

spring基本配置(略过)

开发定义注解

注解的定义


@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Patch {
    String  key() default "";
    String  value() default "";
}

注解实现


@Component
@Aspect
public class PatchAspect {

    @After("Patch()")
    public void after(JoinPoint joinPoint)  {
        // 记录参数
    }

    @AfterReturning(pointcut = "Patch()",returning="returnValue")
    public void afterJoinPoint(JoinPoint joinPoint ,Object returnValue){
        // 记录返回值
    }


    @Pointcut("@annotation(注解路径)")
    public void patch(){}

    @Around("Patch()")
    public void around(ProceedingJoinPoint joinPoint){
        try {

            StopWatch sw = new StopWatch();
            sw.start();
            //获取方法参数
            Object[] args = joinPoint.getArgs();
            MethodSignature sign = (MethodSignature) joinPoint.getSignature();
            String[] parameterNames = sign.getParameterNames();
            System.out.println("parameter list: ");
            for (int i = 0; i < parameterNames.length; i++) {
                System.out.println(parameterNames[i] + " = " + args[i]);
                // 这里可以通过参数名配合注解的值直接修改对应的参数 做拦截操作或者参数校验

            }
            //获取注解参数
            Patch annotation =  sign.getMethod().getAnnotation(Patch.class);
            System.out.println("value = " + annotation.value());
            System.out.println("key = " + annotation.key());

            /*
            // 这里可以不知道注解的情况下获取注解
            Annotation[][] annotations;
            try {
                annotations = pjp.getTarget().getClass().
                        getMethod(methodName, parameterTypes).getParameterAnnotations();
            } catch (Exception e) {
                throw new SoftException(e);
            }

            */

            //执行方法
            joinPoint.proceed();

            //方法执行后逻辑
            sw.stop(args);
            System.out.println(sw.prettyPrint());

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

总结

注解本质意义上就是代码的注释,如果没有实现解析的逻辑那么仅仅是注释。 对于注释有两种方式,一种是编译直接扫描,一种是运行时反射。 注意:基于 java 注解的开发不同于动态语言的简单逻辑,很多时候需要在代码中有效的处理各种类型的判断以及各种未知。

比如在python中类似的功能称为装饰器 下面为python装饰器的实现可能有助于大家更好的理解。


def run_time(func):
    """Decorator for calculating function runtime.
    Arguments:
        func {function}
    Returns:
        function
    """

    def inner(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        ret = time.time() - start
        if ret < 1e-6:
            unit = "ns"
            ret *= 1e9
        elif ret < 1e-3:
            unit = "us"
            ret *= 1e6
        elif ret < 1:
            unit = "ms"
            ret *= 1e3
        else:
            unit = "s"
        print("Total run time is %.1f %s\n" % (ret, unit))
        return res

    return inner

@run_time
def test():
    pass

业务场景使用:

  1. 代码性能分析 (记录分析入参、返回值以及输出函数执行时间)
  2. 业务日志记录 (统一记录相同功能的代码块的业务日志)
  3. 代码段的统一异常处理
  4. 为已有代码添加额外的逻辑 (在不改动代码的基础之上实现)

参考资料

JAVA 注解的基本原理