# 消除代码中的if(二)

通过消除代码中的if(一), 我也发现了缺点:如果 if 的条件很多,那么就需要创建很多个Class类来实现 IConsumerHandler ,这样代码不够简洁。(思路借鉴了XXL-JOB的源码)

当我们看到 KafkaListener 注解的实现方式以后,也可以按照它的方式进一步优化。

一个类中,通过方法上的注解,完成 if - else 的简化。

实现原理代码

# 定义个方法上的新注解@RocketmqListener (opens new window)

注解作用在方法上

/**
 * 事件监听 - 方法
 *
 * @author :    zhangquansheng
 * @date :    2020/4/15 16:09
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RocketmqListener {

    String[] tags() default {};
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 消费者工厂ConsumerFactory (opens new window)

增加 initConsumerHandlerMethodRepository 用于初始化RocketmqListener注解的方法,然后根据当前bean那么和方法名,动态生成对应的class(这里就是简化类的数量的核心逻辑)

/**
 * 消费者工厂
 *
 * @author :    quansheng.zhang
 * @date :    2019/8/13 0:21
 */
@Slf4j
public class ConsumerFactory implements ApplicationContextAware {
 
    @Autowired
    private ApplicationContext applicationContext;
 
    public static Map<String, Class<IConsumerHandler>> consumerHandlerBeanMap = Maps.newConcurrentMap();
 
    /**
     * 获取实体
     *
     * @param event 事件
     * @return IConsumerHandler
     */
    public IConsumerHandler create(String event) {
        Class<IConsumerHandler> consumerHandlerClass = consumerHandlerBeanMap.get(event);
        if (consumerHandlerClass == null) {
            return null;
        }
        return applicationContext.getBean(consumerHandlerClass);
    }
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 
        // init ConsumerHandler Repository
        initConsumerHandlerRepository(applicationContext);
 
        // init ConsumerHandler Repository (for method)
        initConsumerHandlerMethodRepository(applicationContext);
    }
 
    private void initConsumerHandlerRepository(ApplicationContext applicationContext) {
        if (applicationContext == null) {
            return;
        }
        Map<String, Object> evenMap = applicationContext.getBeansWithAnnotation(Event.class);
        evenMap.forEach((k, v) -> {
            Class<IConsumerHandler> consumerHandlerClass = (Class<IConsumerHandler>) v.getClass();
            for (String tag : consumerHandlerClass.getAnnotation(Event.class).tags()) {
                consumerHandlerBeanMap.put(tag, consumerHandlerClass);
            }
        });
    }
 
    private void initConsumerHandlerMethodRepository(ApplicationContext applicationContext) {
        if (applicationContext == null) {
            return;
        }
 
        // init consumer handler from method
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);
            Method[] methods = bean.getClass().getDeclaredMethods();
            for (Method method : methods) {
                RocketmqListener rocketmqListener = AnnotationUtils.findAnnotation(method, RocketmqListener.class);
                if (rocketmqListener != null) {
                    // tags
                    String[] tags = rocketmqListener.tags();
                    if (tags.length == 0) {
                        throw new RuntimeException("rocketmq-listener method-consumerHandler name invalid, for[" + bean.getClass() + "#" + method.getName() + "] .");
                    }
                    for (String tag : tags) {
                        if (consumerHandlerBeanMap.get(tag) != null) {
                            throw new RuntimeException("rocketmq-listener consumerHandler[" + tag + "] naming conflicts.");
                        }
                    }
 
                    // execute method
                    if (!(method.getParameterTypes() != null && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {
                        throw new RuntimeException("rocketmq-listener method-consumerHandler param-class-type invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
                                "The correct method format like \" public Action execute(String param) \" .");
                    }
                    if (!method.getReturnType().isAssignableFrom(Action.class)) {
                        throw new RuntimeException("rocketmq-listener method-consumerHandler return-class-type invalid, for[" + bean.getClass() + "#" + method.getName() + "] , " +
                                "The correct method format like \" public Action execute(String param) \" .");
                    }
                    method.setAccessible(true);
 
 
                    for (String tag : tags) {
                        consumerHandlerBeanMap.put(tag, (Class<IConsumerHandler>) new MethodConsumerHandler(bean, method).getClass());
                    }
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

# 方法 消费者处理MethodConsumerHandler (opens new window)

方法消费者处理者,实现IConsumerHandler,通过反射找到对应的方法

/**
 * 方法 消费者处理
 *
 * @author :    zhangquansheng
 * @date :    2020/4/15 16:31
 */
@Slf4j
public class MethodConsumerHandler implements IConsumerHandler {
 
    private final Object target;
    private final Method method;
 
    public MethodConsumerHandler(Object target, Method method) {
        this.target = target;
        this.method = method;
    }
 
    @Override
    public Action execute(String body) {
        try {
            return (Action) method.invoke(target, new Object[]{body});
        } catch (Exception e) {
            log.error("method:[{}],body:[{}],execute exception:[{}]", method, body, e.getMessage(), e);
            return Action.ReconsumeLater;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

总结

通过以上的注解,可以大量的减少类的数量,推荐使用此注解。

Last Updated: 3 years ago