首页 > 其他分享 >service.getClass().getAnnotation(XXXAnnotation.class) 取值为Null

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

时间:2023-09-26 14:44:37浏览次数:38  
标签:XxxService getClass service public XXXAnnotation XxxType annotation class

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);
            });
        });
    }

这样就能正确的获得注解,并完成工厂类的初始化啦

标签:XxxService,getClass,service,public,XXXAnnotation,XxxType,annotation,class
From: https://www.cnblogs.com/wandoupeas/p/annotation_null.html

相关文章

  • java实现一个接口多个实现类,并且调用指定实现方法@Service
    接口packagecn.daenx.framework.notify.sms.service;importcn.daenx.framework.common.vo.system.utils.SmsSendResult;importjava.util.Map;/***短信接口*/publicinterfaceSmsService{SmsSendResultsendSms(Map<String,String>info,Stringphone......
  • Service mesh 学习03 Istio安装
    一、Kubernetes环境......
  • Microservice - What are microservices, and why are microservices?
    Theconceptof microservicesissimplybreakingasinglelargepotentialserviceintomanysmaller servicesthatworktogether,hence,thename.Oneveryobviousadvantagewhenitcomestobuildinganapplicationwitha microservicearchitecturewouldbe......
  • 【Azure App Services】多次操作App Service伸缩实例遇见限制操作记录
    问题描述多次操作AppServices,进行实例数的变化。达到限制后遇见报错:错误的具体描述为:{"status":"Failed","error":{"code":"Conflict","message":"Youhaveexceededthemaximumamountofscalechange......
  • OGG报错 INS-85054 in oggca.sh createing a new Service Manager after removing a p
    这个报错主要是ogg的自启动和目录问题DeletethefollowingfilesattheOSlevel:Linux7/etc/systemd/system/OracleGoldenGate.service/etc/oggInst.locLinux6/etc/init.d/OracleGoldenGate/etc/rc.d/*OracleGoldenGate/etc/rc*.d/*OracleGoldenGate/etc/oggInst......
  • 什么是 Service Ticket 的 Service Level Agreement
    服务工单(Ticket)的服务级别协议(ServiceLevelAgreement,SLA)是一个重要的概念,特别是在提供技术支持和客户服务的领域中。服务工单是组织内或与客户之间的通信记录,用于跟踪问题、请求或任务的处理。SLA是一种协议或承诺,其中规定了一组指标和参数,以确保服务工单得到适时、高质量的处理......
  • Service mesh 学习02 Istio基础
    一、Istio架构概述1.Pilot提供服务发现和路由规则2.Mixer策略控制:服务调用限流3.citadel安全作用,可以保证服务间的通信安全4.Enovy代理:处理服务的流量二、自动注入sidecar-injector:会修改应用程序的描述信息,注入sidecar描述信息:创建pod的yaml文件三、流量拦截根据iptables路由规......
  • 一文弄懂Java线程池 + Runnable多线程 + 调用WebService接口
    大家好,我是哪吒。一、需求很简单根据接口文档,调用第三方webservice接口,拼接入参,处理回参。RPC调用Webservice接口是一种远程调用的方式,通过指定Webservice接口的调用地址、命名空间、调用的方法名调用远程接口获取结果。二、解决方案通过ExecutorService新建线程池;定义thread类,请......
  • OpenLDAP:使用Self Service Password管理用户密码
    安装dockeryum-yinstalldocker拉取镜像dockerpullgrams/ltb-self-service-password编辑配置文件<?php#==============================================================================#LTBSelfServicePassword##Copyright(C)2009ClementOUDOT#Co......
  • Name or service not known异常处理方法总结
    本人用VmWorkStationPro搭建立centos7环境,在配置静态ip后,虚机与物理主机网络连通,但是虚机却无法访问外网,贴个图吧 也就是Nameorservicenotknown这个错误。本人虚拟机网络为桥接,物理主机连接的是家里的wifi。以下是本人解决无法访问外网的步骤:1.cd/etc/sysconfig/networ......