Tigase8.0 引用了IoC(控制反轉)和DI(依賴注入) 等技術手段,來對對象的創建和控制。不懂的百度下就知道了,Spring完美的實現IOC ,貼一段解釋:
通俗地說:控制反轉IoC(Inversion of Control)是說創建對象的控制權進行轉移,以前創建對象的主動權和創建時機是由自己把控的,而現在這種權力轉移到第三方,比如轉移交給了IoC容器,它就是一個專門用來創建對象的工廠,你要什么對象,它就給你什么對象,有了 IoC容器,依賴關系就變了,原先的依賴關系就沒了,它們都依賴IoC容器了,通過IoC容器來建立它們之間的關系。
DI(依賴注入)其實就是IOC的另外一種說法,DI是由Martin Fowler 在2004年初的一篇論文中首次提出的。他總結:控制的什么被反轉了?就是:獲得依賴對象的方式反轉了。
在Tigase8 中,IOC容器由 Kernel 類實現,Kernel是充當容器管理所有類的依賴對象的注入。
類似Spring 的bean ,在Tigase中,只要是類標有 @Bean(name = "xxx", parent = Kernel.class, active = true) ,標有Bean注解的類,表明該類的對象創建交由容器負責生成
類屬性字段上標有 @Inject(bean = "kernel") 注解時,表明該字段交由容器來賦值
Tigase8 中大量使用JAVA8 Function及Stream編程,需要補充基礎的同學,可以 https://github.com/CarpenterLee/JavaLambdaInternals 進行學習!
下面開始進行代碼的粗略講解,其實 由7到8過渡,核心的架構思想是沒有多大變化的,8中只是加入對象的創建管理手段而已,也可以看以前的文章來了解每個組件之間的邏輯關系
入口類 public final class XMPPServer
public static void start(String[] args) { ... bootstrap = new Bootstrap(); bootstrap.init(args); //加載配置文件等參數 bootstrap.start(); //啟動系統所有的工作組件進行提供服務 }
啟動包裝類 public class Bootstrap
public void start() { //跳過些次要代碼 ...... //類加載工具類 classUtilBean = (ClassUtilBean) Class.forName("tigase.util.reflection.ClassUtilBean").newInstance(); //通過查找classpath下的jar,或dir,並且跳過一些過濾的包路徑,加載所有的類的Class對象,為后面程序能通過@Bean注解能查找到所有需要容器管理的類 classUtilBean.initialize(ClassUtilBean.getPackagesToSkip(null)); // 注冊默認類型轉換器和屬性bean配置器 kernel.registerBean(DefaultTypesConverter.class).exportable().exec(); // DSLBeanConfigurator 注冊到Kernel的beanInstances中,DSLBeanConfiguratorWithBackwardCompatibility 向下兼容的配置文件管理類,對於Tigase來說非常重要,也就是各種Bean加載的入口 kernel.registerBean(DSLBeanConfiguratorWithBackwardCompatibility.class).exportable().exec(); DSLBeanConfigurator configurator = kernel.getInstance(DSLBeanConfigurator.class); configurator.setConfigHolder(config); // 加載所有@Bean(name = "message-router", parent = Kernel.class, active = true) Bean中 parent = Kernel.class 的類,並進行注冊到Kernel容器中,如下圖所示: configurator.registerBeans(null, null, config.getProperties()); // 啟動路由組件的服務 MessageRouter mr = kernel.getInstance("message-router"); mr.start(); }
如下圖所示,查找標有@Bean注解,並且parent=Kernel.class 的Bean集合的Class,並且進行實例化,注冊到Kernel中
一、重點來說下 AbstractBeanConfigurator.registerBeans(null, null, config.getProperties()); 加載查找標有@Bean注解,並且parent=Kernel.class 的Bean,注冊到Kernel中
public void registerBeans(BeanConfig beanConfig, Object bean, Map<String, Object> values) {
//查找標有@Bean注解,並且parent=Kernel.class 的Bean集合 final Map<String, Class<?>> beansFromAnnotations = getBeanClassesFromAnnotations(kernel, beanConfig == null ? Kernel.class : beanConfig.getClazz());
.... //遍歷所查找到的Bean集合,進行注冊到Kernel中 beansFromAnnotations.forEach((name, cls) -> { kernel.registerBean(cls) .setSource(BeanConfig.Source.annotation) .registeredBy(beanConfig) .execWithoutInject();
.... }
查找@Bean中parent屬性為參數類型的Bean
public static Map<String, Class<?>> getBeanClassesFromAnnotations(Kernel kernel, Class<?> requiredClass) { //從classpath加載到的Class集合中 Set<Class<?>> classes = ClassUtilBean.getInstance().getAllClasses(); //遍歷這些Class查找出標有@Bean注解,並且parent屬性為requiredClass類型的bean Class List<Class<?>> toRegister = registerBeansForBeanOfClassGetBeansToRegister(kernel, requiredClass, classes); //轉換下返回類型 Map<String, Class<?>> result = new HashMap<>(); for (Class<?> cls : toRegister) { Bean annotation = cls.getAnnotation(Bean.class); result.put(annotation.name(), cls); } return result; }
二、啟動路由組件的服務,
// 啟動路由組件的服務 MessageRouter mr = kernel.getInstance("message-router"); mr.start();
在執行getInstance()的時候,對還沒初始化的對象進行初始化,進行依賴注入等操作
在首次獲取Bean實例對象的時候,針對bean對象進行一些配置操作,和依賴注入操作,此后,bean實例才是一個完整的對象,其實和Spring中bean的獲取原理是差不多的,不過這里要單純很多,簡單些
protected void initBean(BeanConfig tmpBC, Set<BeanConfig> createdBeansConfig, int deep){ .... //構建延遲依賴注入的本地線程隊列 DelayedDependencyInjectionQueue queue = beanConfig.getKernel().beginDependencyDelayedInjection(); //針對於初始化的Bean判斷是否為系統所默認的配置管理類,如果不是配置管理類本身,則其它類需要調用配置管理類的configure()方法進行配置項處理,如標有@ConfigField的字段 if (beanConfig.getKernel().isBeanClassRegistered(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME) && !beanConfig.getBeanName().equals(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME)) { beanConfigurator = beanConfig.getKernel().getInstance(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME); } else { beanConfigurator = null; }
....
//如果不是默認配置類,則需要進行配置類的configure方法進行處理 if (beanConfigurator != null) {
//此方法會加載@Bean(name = "message-router", parent = beanConfig.clazz.class, active = true),加載@Bean注解中parent為參數beanConfig.clazz類型的Bean,並注冊到Kernel中,下面會重點分解:1 beanConfigurator.configure(beanConfig, bean); } else { //如果是默認配置類本身,則進行配置類對象的創建和注冊到kernel中 AbstractBeanConfigurator.registerBeansForBeanOfClass(beanConfig.getKernel(), bean.getClass()); } //這個是線程私有隊列,這里進行清理工作 beanConfig.getKernel().finishDependecyDelayedInjection(queue); //這里重點,針對@Bean中所有@Inject注解的字段,進行依賴搜索和依賴注入操作 for (final Dependency dep : beanConfig.getFieldDependencies().values()) { beanConfig.getKernel().injectDependencies(bean, dep, createdBeansConfig, deep, false); } //如果實現Initializable 接口,則觸發.initialize()函數的調用 // there is no need to wait to initialize parent beans, it there any? if (bean instanceof Initializable && beanConfig.getState() != State.initialized) { ((Initializable) bean).initialize(); } }
1、重點談下 beanConfigurator.configure(beanConfig, bean);
public void configure(BeanConfig beanConfig, Object bean) throws KernelException { try { grabDefaultConfig(beanConfig, bean); Map<String, Object> ccc = getConfiguration(beanConfig); configure(beanConfig, bean, ccc);//調用父類的配置方法 } catch (Exception e) { throw new KernelException("Cannot inject configuration to bean " + beanConfig.getBeanName(), e); } }
重點進入父類的configure()方法,查找出@bean注冊中parent=beanConfig.clazz類型的Class,進行注冊到Kernel容器中
public void AbstractBeanConfigurator.configure(BeanConfig beanConfig, Object bean, Map<String, Object> values) { ........ //查找@Bean中parent屬性為參數beanConfig.clazz的類,並加載到Kernel容器中 registerBeans(beanConfig, bean, values); ......... }
根據查找到的Bean Class,進行注冊,同時涉及到依賴到別的Bean,則判斷當前本地線程中是否延遲注入隊列,有值,則放到隊列中,運行完本操作后,在.finishDependecyDelayedInjection(queue);中完成注入
public void registerBeans(BeanConfig beanConfig, Object bean, Map<String, Object> values) { if (beanConfig != null && Kernel.class.isAssignableFrom(beanConfig.getClazz())) { return; } //獲得核心的容器管理類 Kernel kernel = beanConfig == null ? this.getKernel() : beanConfig.getKernel(); //找出beanConfig.clazz已經注冊的Bean,用於取消注冊 Set<String> toUnregister = new ArrayList<>(kernel.getDependencyManager().getBeanConfigs()).stream() .filter(bc -> bc.getSource() == BeanConfig.Source.configuration) .filter(bc -> beanConfig == null || bc.getRegisteredBy().contains(beanConfig)) .map(bc -> bc.getBeanName()) .collect(Collectors.toSet()); //遍歷classpath中過濾出來的全部Class,查找出標有@Bean注解,並且parent屬性為Kernel.class或beanConfig.getClazz()類型的bean Class final Map<String, Class<?>> beansFromAnnotations = getBeanClassesFromAnnotations(kernel, beanConfig == null ? Kernel.class : beanConfig.getClazz()); //查找該配置參數中為BeanDefinition的配置項 final Map<String, BeanDefinition> beanDefinitionsFromConfig = values == null ? new HashMap<>() : mergeWithBeansPropertyValue(getBeanDefinitions(values), values); ///遍歷查找出來的beanConfig.clazz類型子Bean集合,依次進行注冊到Kernel容器中 beansFromAnnotations.forEach((name, cls) -> { if (beanDefinitionsFromConfig != null) { BeanDefinition definition = beanDefinitionsFromConfig.get(name); if (definition != null) { return; } } if (isBeanClassRegisteredInParentKernel(kernel.getParent(), name, cls)) { return; } BeanConfig bc = kernel.getDependencyManager().getBeanConfig(name); if (bc != null && bc.getSource() == BeanConfig.Source.annotation && bc.getClazz().equals(cls)) { return; } if (beanConfig != null && beanConfig.getState() == BeanConfig.State.initialized) { kernel.registerBean(cls).setSource(BeanConfig.Source.annotation).registeredBy(beanConfig).exec(); } else { //后面要重點講解下注冊,注冊到kernel容器中。當注冊A對象時,可能會依賴到B對象,所以注冊里有使用到本地線程延遲注冊隊列 kernel.registerBean(cls) .setSource(BeanConfig.Source.annotation) .registeredBy(beanConfig) .execWithoutInject(); } bc = kernel.getDependencyManager().getBeanConfig(name); if (bc != null && bc.getState() == BeanConfig.State.inactive && hasDirectConfiguration(bc)) { log.log(Level.CONFIG, "bean " + bc.getBeanName() + " is disabled but configuration is specified"); } }); //根據參數中為BeanDefinition的配置項,查看該Bean是否已經注冊,沒有則進行注冊 for (BeanDefinition cfg : beanDefinitionsFromConfig.values()) { try { Class<?> clazz = cfg.getClazzName() == null ? beansFromAnnotations.get(cfg.getBeanName()) : ModulesManagerImpl.getInstance().forName(cfg.getClazzName()); BeanConfig oldBc = kernel.getDependencyManager().getBeanConfig(cfg.getBeanName()); if (clazz == null) { if (bean != null && bean instanceof RegistrarBeanWithDefaultBeanClass) { clazz = ((RegistrarBeanWithDefaultBeanClass) bean).getDefaultBeanClass(); } else if (oldBc != null) { clazz = oldBc.getClazz(); } if (clazz == null) { log.log(Level.WARNING, "unknown class {0} for bean {1}, skipping registration of a bean", new Object[]{cfg.getClazzName(), cfg.getBeanName()}); continue; } } if (!tigase.util.reflection.ClassUtilBean.getInstance().getAllClasses().contains(clazz)) { continue; } toUnregister.remove(cfg.getBeanName()); if (oldBc != null && oldBc.getClazz().equals(clazz) && (oldBc.isExportable() || cfg.isExportable() == oldBc.isExportable())) { kernel.setBeanActive(cfg.getBeanName(), cfg.isActive()); } else { Bean ba = clazz.getAnnotation(Bean.class); BeanConfigBuilder cfgBuilder = kernel.registerBean(cfg.getBeanName()).asClass(clazz); cfgBuilder.setActive(cfg.isActive()).setSource(BeanConfig.Source.configuration); if (cfg.isExportable()) { cfgBuilder.exportable(); } if (ba != null) { if (ba.exportable()) { cfgBuilder.exportable(); } } cfgBuilder.registeredBy(beanConfig); if (beanConfig != null && beanConfig.getState() == BeanConfig.State.initialized) { cfgBuilder.exec(); } else { cfgBuilder.execWithoutInject(); } } } catch (ClassNotFoundException ex) { log.log(Level.FINER, "could not register bean '" + cfg.getBeanName() + "' as class '" + cfg.getClazzName() + "' is not available", ex); } } toUnregister.forEach(beanName -> kernel.unregister(beanName)); }
重點講解下注冊,當執行注冊但還沒依賴注入的函數。
public BeanConfig BeanConfigBuilder.execWithoutInject() { if (beanConfig == null) { log.warning("Bean " + clazz + " cannot be registered, because Kernel cannot create configuration for this bean."); kernel.currentlyUsedConfigBuilder = null; return null; } //執行bean的注冊 beanConfig = kernel.registerBean(beanConfig, factoryBeanConfig, beanInstance); return beanConfig; }
注冊bean實例到Kernel.beanInstances中,bean中所依賴inject的類型,注冊到dependencyManager.beanConfigs中,beanConfig通過state來區分,是否為初始化完成的實例
protected BeanConfig Kernel.registerBean(BeanConfig beanConfig, BeanConfig factoryBeanConfig, Object beanInstance) { BeanConfig parent = null; if (beanConfig.getSource() == BeanConfig.Source.annotation && !beanConfig.getRegisteredBy().isEmpty()) { BeanConfig bc = dependencyManager.getBeanConfig(beanConfig.getBeanName()); parent = beanConfig.getRegisteredBy().iterator().next(); if (bc != null && bc.getClazz().equals(beanConfig.getClazz())) { bc.addRegisteredBy(parent); parent.addRegisteredBean(bc); currentlyUsedConfigBuilder = null; return bc; } } if (factoryBeanConfig != null) { factoryBeanConfig.setPinned(beanConfig.isPinned()); factoryBeanConfig.setState(beanConfig.getState()); unregisterInt(factoryBeanConfig.getBeanName()); dependencyManager.register(factoryBeanConfig); } BeanConfig oldBeanConfig = dependencyManager.getBeanConfig(beanConfig.getBeanName()); Collection<Dependency> oldDeps = oldBeanConfig == null ? null : dependencyManager.getDependenciesTo(oldBeanConfig); unregisterInt(beanConfig.getBeanName()); //注冊進依賴管理類 dependencyManager.register(beanConfig); if (parent != null) { parent.addRegisteredBean(beanConfig); } //當實例對象不為空,則更新bean的狀態為initialized if (beanInstance != null) { putBeanInstance(beanConfig, beanInstance); beanConfig.setState(State.initialized); } //查找出本bean可以注入的被依賴集合,簡單地說是B 對象內有個依賴注入的A屬性,現在beanConfig為A實現類,此時這里就可以查找出B對象這個依賴項包裝類Dependency Collection<Dependency> deps = dependencyManager.getDependenciesTo(beanConfig); if (oldDeps != null) { deps.addAll(oldDeps.stream().filter(od -> { Field f = od.getField(); return !deps.stream().anyMatch(nd -> nd.getField().equals(f)); }).collect(Collectors.toSet())); } currentlyUsedConfigBuilder = null; //如果此函數在所在的本地線程內有延遲注入隊列,則加入隊列,在finishDependecyDelayedInjection(queue);進行給依賴本beanConfig類型的對象,進行依賴注入 if (!queueForDelayedDependencyInjection(deps)) {
//當本地線程內無延遲注入隊列則為依賴本beanConfig類的對象立即執行依賴注入 injectDependencies(deps); } return beanConfig; }
前面,我們在 initBean(BeanConfig tmpBC, Set<BeanConfig> createdBeansConfig, int deep) 中有看到 beanConfig.getKernel().finishDependecyDelayedInjection(queue);關於賦值就是在這里進行
private boolean queueForDelayedDependencyInjection(Collection<Dependency> deps) { //本地線程隊列存在的時候,才會放到隊列里去,后面再進行注入 DelayedDependencyInjectionQueue queue = DELAYED_DEPENDENCY_INJECTION.get(); if (queue == null) { return false; } if (deps.isEmpty()) { return true; } queue.offer(new DelayedDependenciesInjection(deps)); return true; }
2.舉個例子進一步說明下,如MessageRouter中依賴注入componentsAll字段,
@Inject private Set<ServerComponent> componentsAll;
當調用initBean時,程序針對 componentsAll字段進行依賴注入,當xxx字段有提供setXxx() 的函數時,系統會自動調用該函數。如MessageRouter中提供 setComponentsAll(Set<ServerComponent> components) 函數,所以,當注入componentsAll字段時,會自動調用setComponentsAll函數
例如在 MessageRouter 需要注入 componentsAll 組件集合對象,就是在getInstance()時觸發的操作
@Bean(name = "message-router", parent = Kernel.class, active = true) public class MessageRouter ..{ @Inject private Set<ServerComponent> componentsAll; public void setComponentsAll(Set<ServerComponent> components) { if (components == null) { return; } HashSet<ServerComponent> removeComponents = new HashSet<>(this.components.values()); removeComponents.removeAll(components); for (ServerComponent comp : removeComponents) { if (comp instanceof ComponentRegistrator) { removeRegistrator((ComponentRegistrator) comp); } else if (comp instanceof MessageReceiver) { removeRouter((MessageReceiver) comp); } else { removeComponent(comp); } if (comp instanceof ConnectionManager) { connectionManagerNames.remove(comp.getName()); } comp.release(); } HashSet<ServerComponent> newComponents = new HashSet<>(components); newComponents.removeAll(this.components.values());
//這里加載到的組件進行相互注冊,通知,和7版本的邏輯是一樣的,可以去看以前的文章 for (ServerComponent comp : newComponents) { try { if (comp instanceof MessageReceiver) { MessageReceiver mr = (MessageReceiver) comp; mr.setParent(this); mr.start(); } if (comp instanceof ConnectionManager) { connectionManagerNames.add(comp.getName()); } if (comp instanceof ComponentRegistrator) { addRegistrator((ComponentRegistrator) comp); } else if (comp instanceof MessageReceiver) { addRouter((MessageReceiver) comp); } else { addComponent(comp); } } catch (ConfigurationException ex) { // TODO - most likely this will no longer happen as configuration will not be done in this method log.log(Level.WARNING, "component " + comp.getName() + " was not configured properly", ex); } } } }
三、最終調用 MessageRouter.start() 啟動路由組件進行,路由功能,和7版本的原理是一樣,這里就不再一一說明,可以找回以前的文章看
到這里啟動篇就完成了,Tigase8,看起來代碼結構改動大,但是其實也沒有多大的變化,核心沒有變,變是的包裝的架子,所以只要認真地看問題不大,在看源碼的同學,建議在調試的時候,再來看這個文章,這樣幫助會大些,可以盡可能快地理解Tigase的原理。
如有不對的地方,請提出來,我進行改進!