注解的优点以及功能
- 动态修改属性
- 动态新增功能(不侵入原代码)
- 动态改变执行逻辑
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
业务场景使用:
- 代码性能分析 (记录分析入参、返回值以及输出函数执行时间)
- 业务日志记录 (统一记录相同功能的代码块的业务日志)
- 代码段的统一异常处理
- 为已有代码添加额外的逻辑 (在不改动代码的基础之上实现)