内容:
1 切面相关
2 自定义注解相关
3 分布式锁
切面:
[https://www.cnblogs.com/Myarticles/articles/11249321.html](https://www.cnblogs.com/Myarticles/articles/11249321.html)
https://blog.csdn.net/jc_benben/article/details/111307755
注意:
1 我们自定义的注解只有放在类上才生效,如果放置到service接口层的话,是不会生效的;(这个有待研究)
接口没有实现方法,spring依赖注入管理的是对象,接口spring可管理不到,既然不是spirng管理的对象,你spirng+aop的配置肯定是失效的
注解是可以继承,但只有类的注解是可以继承的,还需要@Inherited,方法的注解继承不了,spring管理的是实际对象,你加不上注解,更不可能拦截到
你想实现的功能大体上是一种动态实现方法的手段,可以考虑以下:
jdk代理实现接口,然后添加到spring容器中;不过你写这东西有啥用啊。。。。。。。。。。。。
@Inherited是一个标识,用来修饰注解
作用:如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
注意:
接口用上个@Inherited修饰的注解,其实现类不会继承这个注解
父类的**方法**用了@Inherited修饰的注解,子类也不会继承这个注解
当用了@Inherited修饰的注解的@Retention是RetentionPolicy.RUNTIME,则增强了继承性,在反射中可以获取得到
通过代码的结果得知:
子类继承了父类(由于继承特性,子类会拥有父类的公有一切),在通过反射获取子类所有公有字段/方法/构造器的时候,会获取得到自身和父亲的所有public字段/方法/构造器,
而通过反射获取所有任何字段/方法/构造器的时候,只能得到自身的所有任何访问权限修饰符的字段/方法/构造器,不会得到父类的任何字段/方法/构造器。
注解不一样,只有当父类的注解中用@Inherited修饰,子类的getAnnotations()才能获取得到父亲的注解以及自身的注解,而getDeclaredAnnotations()只会获取自身的注解,无论如何都不会获取父亲的注解。
总结:
我们最终可以这样:编写一个自定义的注解;然后编写一个切面类;切点用@annotation的方式标记;这样的话就能实现用自定义注解去统一做某些事情了(如:自定义@BIN,然后,我们写个切面处理,见到这个标签就环绕日志;)这个最大的好处就是灵活,如果用拦截器的话,拦截的是特定包、特定类,不太容易控制到特定方法上;类似的办法其实也可以用拦截器+自定义注解去实现;过程无非就是拦截所有的请求,然后看看懒当前方法上有没有特定的注解;都行;样例代码的话,在《jw+拦截器.md》中有;
@Pointcut("@annotation(com.yjyz.erp.trans.api.finance.serivce.Binc)")
private void lockPoint() {
}
@Around("lockPoint()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("1111111111111111111");
pjp.proceed();
System.out.println("222222222222");
return null;
}
实例
1 这是用AOP + 自定义注解(@SimpleLock) + Redis 做的自定义分布式锁;
package com.yjyz.lock;
import com.yjyz.core.constants.RestExStatus;
import com.yjyz.core.exceptions.BusinessRtException;
import com.yjyz.core.utils.Global;
import com.yjyz.core.utils.bean.SpringELUtils;
import com.yjyz.lock.anno.SimpleLock;
import com.yjyz.lock.anno.SimpleLock.LockFailAction;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
@Aspect
@Configuration
@AutoConfigureAfter({DistributedLockAutoConfiguration.class})
@EnableConfigurationProperties({DistributedLockProperties.class})
@ConditionalOnProperty( //从application.yml中读取配置
prefix = "ub.lock",
name = {"enable"},
havingValue = "true"
)
public class DistributedLockAspect {
private static final Logger log = LoggerFactory.getLogger(DistributedLockAspect.class);
private IDistributedLock distributedLock;
@Autowired
private DistributedLockProperties distributedLockProperties;
public DistributedLockAspect() {
}
@Pointcut("@annotation(com.yjyz.lock.anno.SimpleLock)")
private void lockPoint() {
}
@Around("lockPoint()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
if (this.distributedLock == null) {
this.distributedLock = (IDistributedLock)Global.getBean(IDistributedLock.class);
}
Method method = ((MethodSignature)pjp.getSignature()).getMethod();
SimpleLock redisLock = (SimpleLock)method.getAnnotation(SimpleLock.class); //这里是获得注解
String key = this.distributedLockProperties.getKey() + this.getRediskey(pjp);//这里一大堆代码,就是为了解析spel表达式,拿到key值
// @SimpleLock(action = SimpleLock.LockFailAction.CONTINUE, value = "#econt.id")
// public void verify_binc(EContractVo econt) throws InterruptedException {
//上边解析spel,并将自定义注解中的值取出的过程值得一看;但是本地没有截取;后续查看 DistributedLockAspect.class这个类吧;
int retryTimes = redisLock.action().equals(LockFailAction.CONTINUE) ? redisLock.retryTimes() : 0; //重试次数
boolean lock = this.distributedLock.lock(key, redisLock.keepMills(), retryTimes, redisLock.sleepMills()); //真正获取所得逻辑
if (!lock) {
log.error("get lock failed : " + key);
throw BusinessRtException.of(RestExStatus.SERVICE_LOCKED);
} else {
boolean var12 = false;
Object var7;
try {
var12 = true; // 临时变量
var7 = pjp.proceed(); //开始执行被代理的方法(被环绕的方法)
var12 = false;
} finally {
if (var12) { //如果执行被代理方法异常的话,我们这里手动释放锁
this.distributedLock.releaseLock(key);
}
}
this.distributedLock.releaseLock(key); //如果正常执行完了被代理的方法,这里正常释放锁;
return var7;
}
}
//这是最重要的方法;尝试上锁,如果上锁失败的话,重试;最终返回成功或者失败;
public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {
boolean result;
for(result = this.setRedis(key, expire); !result && retryTimes-- > 0; result = this.setRedis(key, expire)) {
try {
log.debug("lock failed, retrying..." + retryTimes);
Thread.sleep(sleepMillis);
} catch (InterruptedException var9) {
return false;
}
}
return result;
}