zoukankan      html  css  js  c++  java
  • spring自定义注解的使用

    前几天写了一个消息中间件(kafka)的封装,业务方发现消费者需要配置的东西太多(每增加一个topic和实现类都需要在配置文件中加,会显得很繁琐)。于是我为了尽量减少这个XML配置,采用注解的方式来获取topic和实现类。

    第一步:先自定义一个注解,有一个topic的方法用于表明需要监听的topic

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    public @interface TopicSub {
        TopicType topic() ;
    }

    第二步:获取所有使用该注解的类以及注解值

     List<MessageContainer> messageContainerList= Lists.newArrayList();
            Map<String, Object> maps= SpringBeanUtils.getAnnotation(TopicSub.class);
            for (Map.Entry<String, Object> entry : maps.entrySet()) {
                TopicSub topicAnn =  entry.getValue().getClass().getAnnotation(TopicSub.class);
                MessageContainer messageContainer=new MessageContainer(topicAnn.topic().getName());
                messageContainer.setMessageHandle((MessageListener)entry.getValue());
                messageContainerList.add(messageContainer);
            }

    特别说明:SpringBeanUtils.getAnnotation(TopicSub.class)是调用ApplicationContext容器的 getBeansWithAnnotation(Class<? extends Annotation> var1)方法,返回的是所有使用该注解的bean

    然后遍历这个map,拿到每个bean上的注解值(topic方法的值);这里拿bean的注解值的方式是反射.getClass().getAnnotation(),如果bean是放在被代理的包下(service包下一般都是被事务代理了,AOP的实现就是JDK(CJLIB)动态代理),那么.getClass().getAnnotation()这个方法是拿不到注解值的,因为.getClass()拿到的是代理类而不是真正的类,建议这些实现类放在一个不被代理的包下(就是建立一个普通的package即可),如果放在代理包下,那就需要先获取真正的bean,再反射。

    三、监听到消息后,根据topic的值调用实现类

      for (MessageContainer messageContainer : PropertyFactory.consumerProperty.getMessageContainers()) {
                if (consumerRecord.topic().equals(messageContainer.getTopic())) {
                    try {
                        messageContainer.getMessageHandle().onMessage(consumerMessageBO);
                    }catch (KafkaComsumException e){
    }
    }

    四、业务方实现类

    @Component
    @TopicSub(topic = TopicType.SMS_ASYNC_SEND)
    public class SmsMessageHandler  implements MessageListener{
        public  static final Logger log= LoggerFactory.getLogger(SmsMessageHandler.class);
        @Autowired
        private SmsSendLogDao  smsSendLogDao;
        public void onMessage(ConsumerMessageBO consumerMessageBO) throws KafkaComsumException{
            log.info(JSONObject.toJSONString(consumerMessageBO));
            try {
                SmsMessageEO message =JSONObject.parseObject(consumerMessageBO.getMessage().toString(),SmsMessageEO.class);
                for(String phone:message.getPhone() ){
                    SmsResult result= SmsUtils.sendSms(phone,message.getContent(),message.getProduct());
                        SmsSendLogDO smsSendLogDO=new SmsSendLogDO();
                        smsSendLogDO.setContent(message.getContent());
                        smsSendLogDO.setPhone(phone);
                        smsSendLogDO.setProduct(message.getProduct());
                        smsSendLogDO.setCreateTime(new Date());
                        smsSendLogDO.setStatus(result.getCode()==1?1:0);
                        smsSendLogDO.setSender(message.getSender().getName());
                        smsSendLogDao.insert(smsSendLogDO);
                }
            }catch (Exception e){
                throw new KafkaComsumException();
            }
    
        }
    
    }

    前三步都是在jar包中完成(对业务方是透明的),业务方只需要完成第四步消息实现类的逻辑即可(不需要任何xml的配置),有没有感觉很清爽啊!

    这样我们就进一步提升了中间件解耦的程度,其实也满简单的,唯一的坑就是AOP中反射获取到的是代理类这个问题,也是小伙伴们需要注意的!

  • 相关阅读:
    联通手机号停机保号了,想恢复要短信验证码登陆但是无法接收短信验证码怎么办
    记卖饭让我先吃
    POJ 3658 Artificial Lake
    POJ 3662 Telephone Lines (dijstra+二分)
    CodeForces 748C Santa Claus and Robot
    CodeForces 748B Santa Claus and Keyboard Check
    POJ 3659 Cell Phone Network(树形dp树的最小点支配集)
    【JZOJ 5455】拆网线 【树形DP】
    【JZOJ 5455】拆网线 【树形DP】
    【JZOJ 5455】拆网线 【树形DP】
  • 原文地址:https://www.cnblogs.com/zwt1990/p/7018953.html
Copyright © 2011-2022 走看看