背景:根据配置信息,动态生成kafkaListener,springboot提供kafkalistener注解只能通过硬编码方式生成,注解提供的topic pattern可以通过匹配方式接入多个符合规则的topic,但是问题在于这样做不能充分利用多线程方式充分利用系统cpu,kafkalistener生成消费者的方式非常方便,考虑这点,还是在kafkaListener基础上进行开发

1、跟踪源码后发现:springboot调用KafkaListenerAnnotationBeanPostProcessor.postProcessAfterInitialization解析kafkalistener注解,生成kafka消费者,所以可以通过动态生成kafkalistener代码,调用些方法生成消费者

2、java动态编译相关时,在eclipse中通过的代码放在linux环境中时,在代码运行到动态编译处理时报错:无法找到相关包,符号无法识别。在编译时,需要在

CompilationTask getTask(Writer out,
     JavaFileManager fileManager,
     DiagnosticListener<? super JavaFileObject> diagnosticListener,
     Iterable<String> options,
     Iterable<String> classes,
     Iterable<? extends JavaFileObject> compilationUnits);

指定options编译选项,发现,在windows下直接javac -classpath dir时,只需要指定到目录,但是在动态编译中时,需要指定到jar包,多个包时,包间分隔win下为分号,linux下为冒号

3、编译完成后,需要将类加载,发现依赖的其他类not found,原因是使用urlclassloader类加载时,没有指定父loader,定义url loader时传入Thread.currentThread().getContextClassLoader()

4、动态注册bean,最后通过获取bean的方式触发bean生成

        //获取context.
        ApplicationContext ctx =  (ApplicationContext) SpringApplication.run(DynaApp.class, args);
        //获取BeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)ctx.getAutowireCapableBeanFactory();
        //创建bean信息.
        BeanDefinitionBuilder beanDefinitionBuilder =BeanDefinitionBuilder.genericBeanDefinition(Test.class);
        beanDefinitionBuilder.addPropertyValue("name","test");
        //动态注册bean.
        defaultListableBeanFactory.registerBeanDefinition("test",beanDefinitionBuilder.getBeanDefinition());
        //获取动态注册的bean.
        TestService testService =ctx.getBean(Test.class);

5、使用@Configuration ,@Bean,@ConfigurationProperties(prefix = "config.listeners"),将yml配置信息装载,在@Bean时,方法参数同也是动态注入

@Configuration
public class AutoConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "config.listeners")
    public ListenerProperty listenerProps() {
        return new ListenerProperty();
    }
    
}

 

posted on 2020-05-23 13:04  啊哈咧  阅读(2439)  评论(1编辑  收藏  举报