前言
自定义注解目前在我使用过的项目中,主要用用作日志丰富,参数处理,其核心还是借助于Spring的AOP进行实现,本文将结合具体代码演示简单的自定义注解实现流程。
2.实现
2.1 定义User
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
}
2.2 定义UserDAO
@Component
public class UserDao {
public User findUserById(Integer id) {
if(id > 10) {
return null;
}
return new User(id, "user-" + id);
}
}
2.3 定义UserService
@Service
public class UserService {
private final UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public User findUserById(Integer id) {
return userDao.findUserById(id);
}
}
2.4 定义Controller
@RequestMapping(value = "user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User findUser(@PathVariable("id") Integer id) {
return userService.findUserById(id);
}
此时浏览器访问:http://{domain}/user/1即可出现对应效果
{
"id": 1,
"name": "user-1"
}
2.5 定义自定义注解
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
String name() default "";
String value() default "";
}
说明:
● @interface 不是interface,是注解类 定义注解
● Documented
○ 这个Annotation可以被写入javadoc
● @Retention
○ 修饰注解,是注解的注解,称为元注解
○ SOURCE, // 编译器处理完Annotation后不存储在class中
○ CLASS, // 编译器把Annotation存储在class中,这是默认值
○ RUNTIME // 编译器把Annotation存储在class中,可以由虚拟机读取,反射需要
● @Target
○ 注解的作用目标
○ @Target(ElementType.TYPE) //接口、类、枚举、注解
○ @Target(ElementType.FIELD) //字段、枚举的常量
○ @Target(ElementType.METHOD) //方法
○ @Target(ElementType.PARAMETER) //方法参数
○ @Target(ElementType.CONSTRUCTOR) //构造函数
○ @Target(ElementType.LOCAL_VARIABLE) //局部变量
○ @Target(ElementType.ANNOTATION_TYPE) //注解
○ @Target(ElementType.PACKAGE) //包
● 可以定义多个方法,每个方法在使用时参照下面的Controller使用即可,实际就是类似于@PostMapping这样的注解中使用过的value,method,produces等,如下:
2.6 AOP+Controller使用自定义注解
@CustomAnnotation(name = "findUser", value = "根据ID查找用户")
@RequestMapping(value = "user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User findUser(@PathVariable("id") Integer id) {
return userService.findUserById(id);
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TestLogAspect {
@Pointcut("@annotation(cn.test.CustomAnnotation)")
private void pointcut() {}
@Before("pointcut() && @annotation(annotation)")
public void advice(JoinPoint joinPoint, CustomAnnotation annotation) {
System.out.println(
"类名:["
+ joinPoint.getSignature().getDeclaringType().getSimpleName()
+ "],方法名:[" + joinPoint.getSignature().getName()
+ "]-日志内容-[" + annotation.value() + ", "+annotation.name()+ "]");
}
}
3.总结
自定义注解其核心是借助于:@Target 和 @Rentention,@Documented组合实现,其实现还是需要依赖于Spring的AOP进行具体体现,除了上面的用作日志拦截,还可以自定义:数据验证注解,权限注解,缓存注解等多种用途,但其实现基本都遵循上述步骤。