Java注解
java注解是Java提供的一种原程序中的元素关联任何信息和任何元数据的途径和方法。
Java中常见的注解
1、jdk自带注解
Java SE5内置了三种标准注解:
@Override:表示当前的方法定义将要覆盖超类中的方法;
@Deprecated:表示该方法已经过时了。当方法或类上有该注解时,说明该方法或类都已经过期不能再用,但不影响以前的项目使用,提醒你使用心得替代方法或类。如果程序员不小心使用了它的元素,那么编译器会发出警告信息。
@SuppressWarnings:表示忽略指定警告,比如@Suppvisewarnings(“Deprecation”)
使用示例:
2、第三方注解
常见的第三方注解:
Spring:@Autowired、@Resource、@Service、@Repository
MyBatis:@Insert、@Update、@Delete、@Select
注解的分类
-
按照运行机制分
源码注解:只在源码中存在,编译成class文件之后就不存在了;
编译时注解:在源码和class文件中都存在;如JDK自带注解;
运行时注解:在运行阶段起作用,甚至会影响运行逻辑;如@Autowired; -
按照来源分
JDK自带的注解(Java目前只内置了三种标准注解: @Override、@Deprecated、@SuppressWarnings,以及四种元注解:@Target、@Retention、@Documented、@Inherited)
第三方的注解——这一类注解是我们接触最多和作用最大的一类
自定义注解——也可以看作是我们编写的注解,其他的都是他人编写注解
3、自定义注解
1)自定义注解的语法
1)使用 @interface关键自定义注解
2)成员以无参无异常方式声明
3)可以用default为成员指定一个默认值
4)成员类型是受限的,合法的类型包括原始类型及String,class,annotation,enumeration
5)如果注解只有一个成员,在使用时可以忽略成员名和赋值号(=)
6)注解类可以没有成员,没有成员的注解称为标识注解
2)元注解
@interface上面按需要注解上一些东西,包括@Retention、@Target、@Document、@Inherited四种。
3)注解的保留策略:
@Retention(RetentionPolicy.SOURCE) // 注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
4)注解的作用目标:
@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) // 包
5)注解包含在javadoc中:
@Documented
6)注解可以被继承:
@Inherited
7)注解解析器:用来解析自定义注解,注解解析器的原理就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定处理。
自定义注解的使用示例:
1、通过自定义注解进行赋值
2、使用自定义注解结合redis和AOP实现防止重复请求接口
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CacheLock {
/**
* 是否启用缓存锁定
* @return true表示启动,false表示不启动
*/
boolean isAble() default true;
/**
* redis 锁key的前缀
*
* @return redis 锁key的前缀
*/
String prefix() default "";
/**
* 过期秒数,默认为5秒
*
* @return 轮询锁的时间
*/
int expire() default 10;
/**
* 超时时间单位
*
* @return 秒
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* <p>Key的分隔符(默认 :)</p>
* <p>生成的Key:N:SO1008:500</p>
*
* @return String
*/
String delimiter() default ":";
}
@Aspect
@Component
public class LockMethodInterceptor {
private static Logger LOG = LoggerFactory.getLogger(LockMethodInterceptor.class);
@Autowired
public LockMethodInterceptor(RedisLockHelper redisLockHelper) {
this.redisLockHelper = redisLockHelper;
}
private final RedisLockHelper redisLockHelper;
@Autowired
AuthService authService;
@Around("execution(public * *(..)) && @annotation(com.common.web.CacheLock)")
public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
CacheLock lock = method.getAnnotation(CacheLock.class);
if (lock.isAble()) {
final String lockKey = getLockKey(pjp);
String value = UUID.randomUUID().toString();
try {
// 假设上锁成功,但是设置过期时间失效,以后拿到的都是 false
final boolean success = redisLockHelper.lock(lockKey, value, lock.expire(), lock.timeUnit());
if (!success) {
throw new CustomException(405, "重复请求");
}else {
}
return proceed(pjp);
} finally {
redisLockHelper.unlock(lockKey, value);
}
}else {
return proceed(pjp);
}
}
private Object proceed(ProceedingJoinPoint pjp){
try {
return pjp.proceed();
}catch (Throwable e){
return ResponseModel.newFailure(500, "服务端操作失败");
}
}
/**
* 生成锁key的方法
* @param pjp
* @return
*/
public String getLockKey(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
CacheLock lockAnnotation = method.getAnnotation(CacheLock.class);
String token = AuthConts.getToken();
String key = token + lockAnnotation.delimiter() + AuthConts.getUri();
return "jg:lock:"+lockAnnotation.prefix() + lockAnnotation.delimiter() + key;
}
}