背景:根据配置信息,动态生成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(); } }