service.getClass().getAnnotation(XXXAnnotation.class) 取值为Null

这篇具有很好参考价值的文章主要介绍了service.getClass().getAnnotation(XXXAnnotation.class) 取值为Null。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

springboot2.7 java8

问题

在使用工厂模式封装service时,需要通过service的class获取其类型注解,但是有些工厂类可以取到annotation注解,有些取不到
渠道注解:

/**
 * xxx渠道注解
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XxxType {

    /**
     * 渠道的值为XxxTypeEnum枚举
     */
    XxxTypeEnum value();
}

enum:

/**
 * 枚举类
 */
@Getter
@AllArgsConstructor
public enum XxxTypeEnum {

    X1("X1", "渠道1"),
    X2("X2", "渠道2");

    private final String code;
    private final String message;

    public static XxxTypeEnum getEnumByCode(String code){
        for(XxxTypeEnum value:values()){
            if(StringUtils.equals(value.code, code)){
                return value;
            }
        }
        throw new CommonException("未知的XXX类型");
    }
}

工厂类:

@Component
public class XxxServiceFactory implements ApplicationContextAware {

    /**
     * xxx服务的映射集合
     */
    private static final Map<XxxTypeEnum, XxxService> SERVICE_MAP = new HashMap<>();

    /**
     * 工厂方法获取服务实现
     *
     * @param xxxType 渠道
     * @return 服务
     */
    public static XxxService getService(XxxTypeEnum xxxType) {
        XxxService service = SERVICE_MAP.get(xxxType);
        if (service == null) {
            throw new CommonException("没有匹配的服务实现类");
        }
        return service;
    }

    /**
     * 初始化渠道枚举-xxx服务的映射的映射
     *
     * @param applicationContext 应用上下文
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> serviceMap = applicationContext.getBeansWithAnnotation(XxxType.class);
        if (ObjectUtil.isEmpty(serviceMap)) {
            throw new CommonException("服务映射初始化失败");
        }
        serviceMap.forEach((key, bean) -> {
            if (!(bean instanceof XxxService)) {
                throw new CommonException("注解:" + XxxType.class + ",只能用于" + XxxService.class + "的实现类中");
            }
            XxxService service = (XxxService) bean;
            XxxType annotation = service.getClass().getAnnotation(XxxType.class);
            // annotation 有时为null
            SERVICE_MAP.put(annotation.value(), service);
        });
    }
}
public interface XxxService {

    void test();
    void doSomething();

}

渠道1服务实现类

/**
 * 渠道1xxx服务实现类
 */
@XxxType(XxxTypeEnum.X1)
@Service
@Slf4j
public class X1XxxServiceImpl implements XxxService {

    @Override
    public void test() {
        log.info("测试渠道1 test"); 
    }

    /**
     * 此方法需要事务包裹
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void doSomething() {
        log.info("测试渠道1 do something"); 
    }

}

渠道2服务实现类

/**
 * 渠道1xxx服务实现类
 */
@XxxType(XxxTypeEnum.X2)
@Service
@Slf4j
public class X2XxxServiceImpl implements XxxService {

    @Override
    public void test() {
        log.info("测试渠道2 test"); 
    }

    @Override
    public void doSomething() {
        log.info("测试渠道2 do something"); 
    }

}

解决

以上为部分代码,项目启动时,显示渠道1服务实现类的annotationnull,直接npe,找了半天,发现是因为渠道1内的doSomething方法添加事务注解,因为@Transactional也是基于aop的,所以此时拿到的bean是代理对象,而代理对象的方法是不会把原来父类中的方法的注解加上去的,所以为null,所以换了种方式

...
 /**
     * 初始化渠道枚举-xxx服务的映射的映射
     *
     * @param applicationContext 应用上下文
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> serviceMap = applicationContext.getBeansWithAnnotation(XxxType.class);
        if (ObjectUtil.isEmpty(serviceMap)) {
            throw new CommonException("服务映射初始化失败");
        }
        serviceMap.forEach((key, bean) -> {
            if (!(bean instanceof XxxService)) {
                throw new CommonException("注解:" + XxxType.class + ",只能用于" + XxxService.class + "的实现类中");
            }
            // XxxService service = (XxxService) bean;
            // XxxType annotation = service.getClass().getAnnotation(XxxType.class);
            // SERVICE_MAP.put(annotation.value(), service);
            List<Annotation> list = AnnotationUtil.scanClass(bean.getClass());
            list.stream().filter(annotation -> annotation instanceof XxxType).findFirst().ifPresent(annotation -> {
                XxxType xxxType = (XxxType) annotation;
                SERVICE_MAP.put(xxxType .value(), (XxxService) bean);
            });
        });
    }

这样就能正确的获得注解,并完成工厂类的初始化啦文章来源地址https://www.toymoban.com/news/detail-712102.html

到了这里,关于service.getClass().getAnnotation(XXXAnnotation.class) 取值为Null的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python dict 取值方法

      在日常工作中,我们经常会遇到需要将一些数据转换为 dict格式的情况。比如: 1、想要将多个数组按照某种规则进行排列,形成有序的数据表,这时需要使用 dict函数。 3、想要将数据按照指定的方式进行存储,比如:按行存储、按列存储等,这时需要使用 dict函数。 dict函

    2024年02月08日
    浏览(35)
  • SpringMVC传值与取值

    第一种:ModelAndvie 第二种、Model 第三种、ModelMap modelMap 第四种、Map 第五种、request 1、对象取值 2、注解取值 3、request

    2024年02月02日
    浏览(42)
  • OpenCV 数据类型及赋值取值

     在之前的博客 OpenCV 32F 与 8U Mat数据类型相互转换(C++版) 已经提到,OpenCV Mat 类型及对应编号,如下表:    其中C1~C4为通道数,经常使用的数据类型对应如下表所示:    其中: FLT_MAX = 3.402823466e+38 FLT_MIN = 1.175494351e-38 DBL_MAX = 1.7976931348623158e+308 DBL_MIN = 2.2250738585072014e-308 如果

    2024年02月09日
    浏览(68)
  • 从URL取值传给后端

    点击浏览文章详情,跳转至详情页面 从 url 中拿出文章 id,传给后端 首先拿到url 然后判断是否有值,从问号后面取值 params.split(\\\'\\\') 以 作为分割 然后遍历字符数组 paramArr[i].split(\\\"=\\\") ,又用 =等号 分割键和值 判断 key 和传过来的 key 是否一样,一样就返回该 key 对应的 value 值

    2024年02月14日
    浏览(36)
  • java基本数据类型取值范围

    在JAVA中一共有八种基本数据类型,他们分别是  byte、short、int、long、float、double、char、boolean  整型  其中byte、short、int、long都是表示整数的,只不过他们的取值范围不一样  byte的取值范围为-128~127,占用1个字节(-2的7次方到2的7次方-1)  short的取值范围为-32768~32767,占用

    2024年02月12日
    浏览(36)
  • pandas--DataFrame--数据切片/筛选/取值

    2024年02月13日
    浏览(54)
  • 数据结构---HashSet存值和取值

    HashMap实现了Map接口,而HashSet实现了Set接口。 HashMap用于存储键值对,而HashSet用于存储对象。 HashMap不允许有重复的键,可以允许有重复的值。 HashSet不允许有重复元素。 HashMap允许有一个键为空,多个值为空,HashSet允许有一个空值。 HashMap中使用put()将元素加入map中,而HashS

    2024年02月15日
    浏览(39)
  • Python通过Postman取值并返回值

    目录 前言 一、目标 二、代码 1.计算文件 2.取数文件 三、Postman设置 四、执行 五、补充 总结 此文章为个人学习记录,有不足或描述错误之处,请指正。 通过以下代码及设置,可实现作为postman作为前端平台和python作为后端模型的输入、输出测试。 计算文件名称为“calculate

    2024年02月06日
    浏览(25)
  • $route.query.value取值避坑

    问题:在实现从A页面携带参数 (this.$router.push({path:“”,query:{})) 点击按钮到B页面时,发现获取不到参数 原因:因为 JavaScript 中的日期对象不能被直接序列化为 URL 查询参数。我传的是el-date-picker中默认参数Fri Aug 04 2023 11:35:59 GMT+0800 (中国标准时间) 解决办法:传值的时候改为字

    2024年02月05日
    浏览(56)
  • Java List 随机取值的多种方法

    为了从列表中获取随机元素,需要生成一个随机索引号,然后使用 list.get() 方法通过生成的索引编号获取元素。 这里关键是要记住,不得使用超过列表大小的索引。

    2024年02月15日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包