自定义一个注解
前言:因为Spring Boot使用注解取代了Spring繁琐的文件配置,所以我们在使用Spring Boot进行开发的时候不用怎么手写配置文件,只需要在相关程序中添加特定的注解就可以起到相关的作用,使用最广泛的无非就是@RestController、@Service、@Component了。
本人对注解的理解:每个注解就是一个切点,切点的前、后、运行时这三个切面可以进行业务逻辑的添加,也就是在运行一段包含注解的程序前,先运行这个注解所定义的业务逻辑。
定义注解:
/**声明注解的使用范围*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Schema {
//value是注解中属性,默认值为self_introduction
String value() default "self_introduction";
}
拦截注解,添加业务逻辑:
@Component
@Aspect
public class SchemaAspect {
//注解的位置
@Pointcut(value = "@annotation(com.dwk.mybatis.plugin.Schema)")
public void access() {
}
//添加注解的方法或类运行前要执行的业务逻辑
@Before("access()")
public void before(){
}
//添加注解的方法或类运行时要执行的业务逻辑,即方法增强
@Around("access()")
public void around(ProceedingJoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
//注解方法中的参数名
String[] parameterNames = methodSignature.getParameterNames();
//注解方法中的参数值
Object[] args = joinPoint.getArgs();
Method method = methodSignature.getMethod();
//注解的value值
Schema annotation = method.getAnnotation(Schema.class);
System.out.println("注解的值:"+annotation.value());
for (int i = 0;i<parameterNames.length;i++){
System.out.println("方法中的参数和对应的值:"+parameterNames[i]+args[i].toString());
if (("schema").equals(parameterNames[i])){
args[i] = annotation.value();
}
}
}
//添加注解的方法或类运行后要执行的业务逻辑
@After("access()")
public void after(){
}
}
总结:其实就是Spring Boot的AOP理念,在某个地方添加注解,将注解作为切点,然后在一个类中拦截这个注解,并在切点的前、后、运行是做方法的增强。
打个比方:程序就像是高速公路,注解就是收费站,跑到每个收费站都需要停一下完成收费站所需要执行的逻辑,然后才能放行去行驶下一段高速。那么现实中收费站只有个收费的逻辑,但是在程序中我们可以给注解添加被注解的方法执行前要做什么,执行的同时要做什么,执行后又要做什么。
插一段aop的相关知识:
首先 官方文档:https://www.eclipse.org/aspectj/doc/released/index.html
以上这种注解的声明方式在使用的时候,必须要显示的去声明才能生效;那么如果说需要使用到的地方太多,比如说全局的事务处理和异常处理;这个时候使用这种单一的注解声明就显得不太合适了,因为要使用到的地方实在太多了,如果使用这种方式的话容易遗漏不说,还显得特别臃肿;
那么如果要给全局的某一层使用aop来控制一段逻辑的话要怎么实现呢?这个时候就要使用到切入点表达式了。既然是切点表达式,那么自然也就和切点相关了
以上程序中的切点:
@Pointcut(value = “@annotation(com.dwk.mybatis.plugin.Schema)”)
用切点表达式替换一下:
@Pointcut(“execution(public * com.dwk.service.*Service.*(…)))”)
含义:com.dwk.service包下的所有以Service结尾的类下的所有方法都当作切点,也就是这些类的所有方法都不需要加注解即可运行你切面中定义的逻辑,统一且准确;
至于其他的切点表达式就不过多说明了,网上有很多很详细的切点表达式文章。
最后,仅是作者个人理解,若有错误还请指正,谢谢!