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的原理。
如有不對的地方,請提出來,我進行改進!
