排坑日记-获取不到类上的注解?空指针?

点击上方名片关注我,为你带来更多踩坑案例

d9858501dd3715656b112c1290558b51.png

引导

235dafb56e62fea37441e061f8b903c6.gif

废话不多说,本文从现象-原因-解决办法三个方面来简述

解决办法有多种,大家根据自己的情况自行选择

想看解决办法的直接拉到最下面

现象

c42bb9b348d7c2cbb8b2b5dd03533873.gif

使用springboot,在执行类似如下代码的时候

AbstractDataAuthHandler是一个抽象类

类下面有几个标有DataAuthHandler注解的子类,分别实现了不同的功能

想把注解中指定的value作为key,handler作为value,来实现一个简单的根据不同的value调用不同处理类的

@PostConstruct
    public void init() {
        Map<String, AbstractDataAuthHandler> abstractHandlerMap = context.getBeansOfType(AbstractDataAuthHandler.class);
        for (String beanName : abstractHandlerMap.keySet()) {
            AbstractDataAuthHandler handler = abstractHandlerMap.get(beanName);
            DataAuthHandler authHandler = handler.getClass().getAnnotation(DataAuthHandler.class);
            handlerMap.put(authHandler.value(), handler);
        }
    }

然后初始化设值的时候第7行直接报空指针

9e9402d315d7c3d547f5e2d6b6d5debb.png

也就是说 authVlue 没获取到

原因

1d0f6bd4acd2d69ffe2772ca7e9183d4.gif

其实原因很简单,问题无非就是出现在获取authValue注解的时候,debug仔细检查一下就会发现

767249f9b7dbaa6c62fdb7386bc42b3e.png

handler变成了一个代理类???

41d1f804a51aef262ba04f3e7a4895f4.png

果然,被spring代理了。

下面开始尝试解决办法

解决办法1-通过代理类获取原生对象

7d839cb9e4b2debc16d85eb21c679947.gif

话不多说,直接上工具类

package com.iqiyi.scriptevaluationtool.sys.utils;


import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;


import java.lang.reflect.Field;


@Slf4j
public class AopTargetUtils {
    /**
     * 获取 目标对象
     * @param proxy 代理对象
     * @return
     * @throws Exception
     */
    public static Object getTarget(Object proxy) {


        try {
            if(!AopUtils.isAopProxy(proxy)) {
                return proxy;//不是代理对象
            }


            if(AopUtils.isJdkDynamicProxy(proxy)) {
                return getJdkDynamicProxyTargetObject(proxy);
            } else { //cglib
                return getCglibProxyTargetObject(proxy);
            }
        } catch (Exception e) {
            log.error("获取目标对象{}error",proxy,e);
            return proxy;
        }




    }




    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);


        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);


        Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();


        return target;
    }




    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);


        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);


        Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();


        return target;
    }


}

然后获取handler的原生类即可,此方法简单快捷,对原有业务改动不大

解决办法2-不用代理类

214f358a0bf1f6fd425eca46465d4cee.gif

一般来说,类似于AbstractDataAuthHandler这种的类,以及它的子类,既然通过这种方式加载了,其实交付给spring托管的意义也不大,因为在其他地方大概率不会再单独用到了。

所以可以通过@Bean的方式自行加载即可

@Configuration
public class TestConfiguration {


    @Bean
    public ProjectDataAuthHandler projectDataAuthHandler() {
        return new ProjectDataAuthHandler();
    }
}
@PostConstruct
    public void init() {
        Map<String, AbstractHandler> abstractApiAuthHandlerMap = context.getBeansOfType(AbstractHandler.class);
        for (String beanName : abstractApiAuthHandlerMap.keySet()) {
            AbstractHandler handler = abstractApiAuthHandlerMap.get(beanName);
            DataAuthHandler authHandler = handler.getClass().getAnnotation(DataAuthHandler.class);
            handlerMap.put(authHandler.value(), handler);
        }
    }

上述方式也是可行的,只不过子类比较多的时候,可能代码量会略多一些

猜你喜欢

转载自blog.csdn.net/qq_31363843/article/details/128025059
今日推荐