springboot 拦截器之Advisor不生效问题

2023-12-14 16:43:54

SPringBoot使用方法注解拦截器时遇到不生效问题记录:

  1. 定义方法注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DataScope
{
    boolean enable() default true;

}
  1. 定义 Advisor

@Getter
@EqualsAndHashCode(callSuper = true)
@Component
public class DataPermissionAnnotationAdvisor extends AbstractPointcutAdvisor {

    private final Advice advice;

    private final Pointcut pointcut;

    public DataPermissionAnnotationAdvisor() {
        this.advice = new DataScopeAnnotationInterceptor();
        this.pointcut = this.buildPointcut();
    }

    protected Pointcut buildPointcut() {
        Pointcut classPointcut = new AnnotationMatchingPointcut(DataScope.class, true);
        Pointcut methodPointcut = new AnnotationMatchingPointcut(null, DataScope.class, true);
        return new ComposablePointcut(classPointcut).union(methodPointcut);
    }

}
  1. 定义拦截器

public class DataScopeAnnotationInterceptor implements MethodInterceptor {


    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Logger log = LoggerFactory.getLogger(DataScopeAnnotationInterceptor.class);
        log.debug("DataScopeAnnotationInterceptor 拦截器:" + methodInvocation.getMethod().getName());
     
        try {
            // 执行逻辑
            return methodInvocation.proceed();
        } finally {
            // 出栈
            if (dataPermission != null) {
                DataPermissionContextHolder.remove();
            }
        }
    }

}

  1. 在要使用拦截器的方法体上方添加注解
@Service
public class UserService {
    @DataScope
    public void method01() {
        // 查询订单
        UserDO user = userMapper.selectById(1);
        System.out.println(user);
    }
 }

完成以上全部代码,在调用motho01()方法时,正常就应该先执行拦截器,再执行method01中的方法。但在springboot-2.1.3RELEASE版本时,拦截器却没有生效。
网上搜罗一圈没有现成的办法,只能老老实实看源码了,功夫不负有心人,请看以下源码:

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    public InfrastructureAdvisorAutoProxyCreator() {
    }

    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        this.beanFactory = beanFactory;
    }

//在获取拦截器时,通过这个方法判断是否是有效拦截器的意思。
//其中 this.beanFactory.getBeanDefinition(beanName).getRole() == 2 这个条件就是导致拦截器不生效的小虫子。
    protected boolean isEligibleAdvisorBean(String beanName) {
        return this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == 2;
    }
}

解决办法:

  • 只需在DataPermissionAnnotationAdvisor 类上方添加Role(2)这个注解,拦截器就生效了。

像这样就可以了。

@Getter
@EqualsAndHashCode(callSuper = true)
@Component
@Role(2)
public class DataPermissionAnnotationAdvisor extends AbstractPointcutAdvisor {

    private final Advice advice;

    private final Pointcut pointcut;

    public DataPermissionAnnotationAdvisor() {
        this.advice = new DataScopeAnnotationInterceptor();
        this.pointcut = this.buildPointcut();
    }

    protected Pointcut buildPointcut() {
        Pointcut classPointcut = new AnnotationMatchingPointcut(DataScope.class, true);
        Pointcut methodPointcut = new AnnotationMatchingPointcut(null, DataScope.class, true);
        return new ComposablePointcut(classPointcut).union(methodPointcut);
    }

}

@Role注解

  1. 标识Bean的类别
  2. 种类:
    1. ROLE_APPLICATION = 0
    • bean的默认角色
    • 标识应用的主要的主要角色
    • 通常对应于用户定义的bean
    1. ROLE_APPLICATION = 1
    • 标识较大配置的一部分
    • 通常是仔细观察特定的ComponentDefinition时重要的提示,而不是体现在应用中
    1. ROLE_INFRASTRUCTURE = 2
    • 标识后台角色,与最终用户无关
    • 通常供是内部工作的bean使用

通常用户定义的bean,role的值都是0,而springboot内核bean的role值才为2。所以我看到有自动配置插件中没有手动添加Role注解,依然能拦截,我想就是这个原因吧。

其他的办法,欢迎留言补充。

文章来源:https://blog.csdn.net/ldz_wolf/article/details/134993502
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。