内容:

  1. 1 切面相关
  2. 2 自定义注解相关
  3. 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;
    }