背景:根據配置信息,動態生成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(); } }