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

  1. public static void start(String[] args) {
  2. ...
  3. bootstrap = new Bootstrap();
  4. bootstrap.init(args); //加载配置文件等参数
  5. bootstrap.start(); //启动系统所有的工作组件进行提供服务
  6. }

  

  1. 启动包装类 public class Bootstrap
  1. public void start() {
  2. //跳过些次要代码
  3. ......
  4. //类加载工具类
  5. classUtilBean = (ClassUtilBean) Class.forName("tigase.util.reflection.ClassUtilBean").newInstance();
  6. //通过查找classpath下的jar,或dir,并且跳过一些过滤的包路径,加载所有的类的Class对象,为后面程序能通过@Bean注解能查找到所有需要容器管理的类
  7. classUtilBean.initialize(ClassUtilBean.getPackagesToSkip(null));
  8.  
  9. // 注册默认类型转换器和属性bean配置器
  10. kernel.registerBean(DefaultTypesConverter.class).exportable().exec();
  11.  
  12. // DSLBeanConfigurator 注册到Kernel的beanInstances中,DSLBeanConfiguratorWithBackwardCompatibility 向下兼容的配置文件管理类,对于Tigase来说非常重要,也就是各种Bean加载的入口
  13. kernel.registerBean(DSLBeanConfiguratorWithBackwardCompatibility.class).exportable().exec();
  14. DSLBeanConfigurator configurator = kernel.getInstance(DSLBeanConfigurator.class);
  15. configurator.setConfigHolder(config);
  16.  
  17. // 加载所有@Bean(name = "message-router", parent = Kernel.class, active = true) Bean中 parent = Kernel.class 的类,并进行注册到Kernel容器中,如下图所示:
  18. configurator.registerBeans(null, null, config.getProperties());
  19. // 启动路由组件的服务
  20. MessageRouter mr = kernel.getInstance("message-router");
  21. mr.start();
  22. }

  

  1. 如下图所示,查找标有@Bean注解,并且parent=Kernel.class Bean集合的Class,并且进行实例化,注册到Kernel

一、重点来说下 AbstractBeanConfigurator.registerBeans(null, null, config.getProperties()); 加载查找标有@Bean注解,并且parent=Kernel.class 的Bean,注册到Kernel中

  1. public void registerBeans(BeanConfig beanConfig, Object bean, Map<String, Object> values) {
  2. //查找标有@Bean注解,并且parent=Kernel.class 的Bean集合
  3. final Map<String, Class<?>> beansFromAnnotations = getBeanClassesFromAnnotations(kernel, beanConfig == null
  4. ? Kernel.class
  5. : beanConfig.getClazz());
  6. ....
  7. //遍历所查找到的Bean集合,进行注册到Kernel中
  8. beansFromAnnotations.forEach((name, cls) -> {
  9.  
  10. kernel.registerBean(cls)
  11. .setSource(BeanConfig.Source.annotation)
  12. .registeredBy(beanConfig)
  13. .execWithoutInject();
  14.  
  15. ....
  16. }

  

查找@Bean中parent属性为参数类型的Bean

  1. public static Map<String, Class<?>> getBeanClassesFromAnnotations(Kernel kernel, Class<?> requiredClass) {
  2. //从classpath加载到的Class集合中
  3. Set<Class<?>> classes = ClassUtilBean.getInstance().getAllClasses();
  4.      //遍历这些Class查找出标有@Bean注解,并且parent属性为requiredClass类型的bean Class
  5. List<Class<?>> toRegister = registerBeansForBeanOfClassGetBeansToRegister(kernel, requiredClass, classes);
  6. //转换下返回类型
  7. Map<String, Class<?>> result = new HashMap<>();
  8. for (Class<?> cls : toRegister) {
  9. Bean annotation = cls.getAnnotation(Bean.class);
  10. result.put(annotation.name(), cls);
  11. }
  12.  
  13. return result;
  14. }

  

二、启动路由组件的服务,

  1. // 启动路由组件的服务
  2. MessageRouter mr = kernel.getInstance("message-router");
  3. mr.start();

  

在执行getInstance()的时候,对还没初始化的对象进行初始化,进行依赖注入等操作

在首次获取Bean实例对象的时候,针对bean对象进行一些配置操作,和依赖注入操作,此后,bean实例才是一个完整的对象,其实和Spring中bean的获取原理是差不多的,不过这里要单纯很多,简单些

  1. protected void initBean(BeanConfig tmpBC, Set<BeanConfig> createdBeansConfig, int deep){
  2. ....
  3. //构建延迟依赖注入的本地线程队列
  4. DelayedDependencyInjectionQueue queue = beanConfig.getKernel().beginDependencyDelayedInjection();
  5.  
  6. //针对于初始化的Bean判断是否为系统所默认的配置管理类,如果不是配置管理类本身,则其它类需要调用配置管理类的configure()方法进行配置项处理,如标有@ConfigField的字段
  7. if (beanConfig.getKernel().isBeanClassRegistered(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME) &&
  8. !beanConfig.getBeanName().equals(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME)) {
  9. beanConfigurator = beanConfig.getKernel().getInstance(BeanConfigurator.DEFAULT_CONFIGURATOR_NAME);
  10. } else {
  11. beanConfigurator = null;
  12. }
    ....
  1. //如果不是默认配置类,则需要进行配置类的configure方法进行处理
  2. if (beanConfigurator != null) {
    //此方法会加载@Bean(name = "message-router", parent = beanConfig.clazz.class, active = true),加载@Bean注解中parent为参数beanConfig.clazz类型的Bean,并注册到Kernel中,下面会重点分解:1
  3. beanConfigurator.configure(beanConfig, bean);
  4. } else {
  5. //如果是默认配置类本身,则进行配置类对象的创建和注册到kernel中
  6. AbstractBeanConfigurator.registerBeansForBeanOfClass(beanConfig.getKernel(), bean.getClass());
  7. }
  8. //这个是线程私有队列,这里进行清理工作
  9. beanConfig.getKernel().finishDependecyDelayedInjection(queue);
  10.  
  11. //这里重点,针对@Bean中所有@Inject注解的字段,进行依赖搜索和依赖注入操作
  12. for (final Dependency dep : beanConfig.getFieldDependencies().values()) {
  13. beanConfig.getKernel().injectDependencies(bean, dep, createdBeansConfig, deep, false);
  14. }
  15. //如果实现Initializable 接口,则触发.initialize()函数的调用
  16. // there is no need to wait to initialize parent beans, it there any?
  17. if (bean instanceof Initializable && beanConfig.getState() != State.initialized) {
  18. ((Initializable) bean).initialize();
  19. }
  20. }

  

1、重点谈下 beanConfigurator.configure(beanConfig, bean);

  1. public void configure(BeanConfig beanConfig, Object bean) throws KernelException {
  2. try {
  3. grabDefaultConfig(beanConfig, bean);
  4. Map<String, Object> ccc = getConfiguration(beanConfig);
  5. configure(beanConfig, bean, ccc);//调用父类的配置方法
  6. } catch (Exception e) {
  7. throw new KernelException("Cannot inject configuration to bean " + beanConfig.getBeanName(), e);
  8. }
  9. }

  

重点进入父类的configure()方法,查找出@bean注册中parent=beanConfig.clazz类型的Class,进行注册到Kernel容器中

  1. public void AbstractBeanConfigurator.configure(BeanConfig beanConfig, Object bean, Map<String, Object> values) {
  2. ........
  3. //查找@Bean中parent属性为参数beanConfig.clazz的类,并加载到Kernel容器中
  4. registerBeans(beanConfig, bean, values);
  5. .........
  6. }

  

根据查找到的Bean Class,进行注册,同时涉及到依赖到别的Bean,则判断当前本地线程中是否延迟注入队列,有值,则放到队列中,运行完本操作后,在.finishDependecyDelayedInjection(queue);中完成注入

  1. public void registerBeans(BeanConfig beanConfig, Object bean, Map<String, Object> values) {
  2. if (beanConfig != null && Kernel.class.isAssignableFrom(beanConfig.getClazz())) {
  3. return;
  4. }
  5.    //获得核心的容器管理类
  6. Kernel kernel = beanConfig == null ? this.getKernel() : beanConfig.getKernel();
  7. //找出beanConfig.clazz已经注册的Bean,用于取消注册
  8. Set<String> toUnregister = new ArrayList<>(kernel.getDependencyManager().getBeanConfigs()).stream()
  9. .filter(bc -> bc.getSource() == BeanConfig.Source.configuration)
  10. .filter(bc -> beanConfig == null || bc.getRegisteredBy().contains(beanConfig))
  11. .map(bc -> bc.getBeanName())
  12. .collect(Collectors.toSet());
  13. //遍历classpath中过滤出来的全部Class,查找出标有@Bean注解,并且parent属性为Kernel.class或beanConfig.getClazz()类型的bean Class
  14. final Map<String, Class<?>> beansFromAnnotations = getBeanClassesFromAnnotations(kernel, beanConfig == null
  15. ? Kernel.class
  16. : beanConfig.getClazz());
  17. //查找该配置参数中为BeanDefinition的配置项
  18. final Map<String, BeanDefinition> beanDefinitionsFromConfig =
  19. values == null ? new HashMap<>() : mergeWithBeansPropertyValue(getBeanDefinitions(values), values);
  20. ///遍历查找出来的beanConfig.clazz类型子Bean集合,依次进行注册到Kernel容器中
  21. beansFromAnnotations.forEach((name, cls) -> {
  22. if (beanDefinitionsFromConfig != null) {
  23. BeanDefinition definition = beanDefinitionsFromConfig.get(name);
  24. if (definition != null) {
  25. return;
  26. }
  27. }
  28.  
  29. if (isBeanClassRegisteredInParentKernel(kernel.getParent(), name, cls)) {
  30. return;
  31. }
  32.  
  33. BeanConfig bc = kernel.getDependencyManager().getBeanConfig(name);
  34. if (bc != null && bc.getSource() == BeanConfig.Source.annotation && bc.getClazz().equals(cls)) {
  35. return;
  36. }
  37.  
  38. if (beanConfig != null && beanConfig.getState() == BeanConfig.State.initialized) {
  39. kernel.registerBean(cls).setSource(BeanConfig.Source.annotation).registeredBy(beanConfig).exec();
  40. } else {
  41. //后面要重点讲解下注册,注册到kernel容器中。当注册A对象时,可能会依赖到B对象,所以注册里有使用到本地线程延迟注册队列
  42. kernel.registerBean(cls)
  43. .setSource(BeanConfig.Source.annotation)
  44. .registeredBy(beanConfig)
  45. .execWithoutInject();
  46. }
  47.  
  48. bc = kernel.getDependencyManager().getBeanConfig(name);
  49. if (bc != null && bc.getState() == BeanConfig.State.inactive && hasDirectConfiguration(bc)) {
  50. log.log(Level.CONFIG, "bean " + bc.getBeanName() + " is disabled but configuration is specified");
  51. }
  52. });
  53.  
  54. //根据参数中为BeanDefinition的配置项,查看该Bean是否已经注册,没有则进行注册
  55. for (BeanDefinition cfg : beanDefinitionsFromConfig.values()) {
  56. try {
  57. Class<?> clazz = cfg.getClazzName() == null
  58. ? beansFromAnnotations.get(cfg.getBeanName())
  59. : ModulesManagerImpl.getInstance().forName(cfg.getClazzName());
  60. BeanConfig oldBc = kernel.getDependencyManager().getBeanConfig(cfg.getBeanName());
  61. if (clazz == null) {
  62. if (bean != null && bean instanceof RegistrarBeanWithDefaultBeanClass) {
  63. clazz = ((RegistrarBeanWithDefaultBeanClass) bean).getDefaultBeanClass();
  64. } else if (oldBc != null) {
  65. clazz = oldBc.getClazz();
  66. }
  67.  
  68. if (clazz == null) {
  69. log.log(Level.WARNING, "unknown class {0} for bean {1}, skipping registration of a bean",
  70. new Object[]{cfg.getClazzName(), cfg.getBeanName()});
  71. continue;
  72. }
  73. }
  74.  
  75. if (!tigase.util.reflection.ClassUtilBean.getInstance().getAllClasses().contains(clazz)) {
  76. continue;
  77. }
  78.  
  79. toUnregister.remove(cfg.getBeanName());
  80.  
  81. if (oldBc != null && oldBc.getClazz().equals(clazz) &&
  82. (oldBc.isExportable() || cfg.isExportable() == oldBc.isExportable())) {
  83. kernel.setBeanActive(cfg.getBeanName(), cfg.isActive());
  84. } else {
  85. Bean ba = clazz.getAnnotation(Bean.class);
  86. BeanConfigBuilder cfgBuilder = kernel.registerBean(cfg.getBeanName()).asClass(clazz);
  87. cfgBuilder.setActive(cfg.isActive()).setSource(BeanConfig.Source.configuration);
  88. if (cfg.isExportable()) {
  89. cfgBuilder.exportable();
  90. }
  91. if (ba != null) {
  92. if (ba.exportable()) {
  93. cfgBuilder.exportable();
  94. }
  95. }
  96.  
  97. cfgBuilder.registeredBy(beanConfig);
  98.  
  99. if (beanConfig != null && beanConfig.getState() == BeanConfig.State.initialized) {
  100. cfgBuilder.exec();
  101. } else {
  102. cfgBuilder.execWithoutInject();
  103. }
  104. }
  105. } catch (ClassNotFoundException ex) {
  106. log.log(Level.FINER,
  107. "could not register bean '" + cfg.getBeanName() + "' as class '" + cfg.getClazzName() +
  108. "' is not available", ex);
  109. }
  110. }
  111.  
  112. toUnregister.forEach(beanName -> kernel.unregister(beanName));
  113. }

  

  

重点讲解下注册,当执行注册但还没依赖注入的函数。

  1. public BeanConfig BeanConfigBuilder.execWithoutInject() {
  2. if (beanConfig == null) {
  3. log.warning("Bean " + clazz +
  4. " cannot be registered, because Kernel cannot create configuration for this bean.");
  5. kernel.currentlyUsedConfigBuilder = null;
  6. return null;
  7. }
  8. //执行bean的注册
  9. beanConfig = kernel.registerBean(beanConfig, factoryBeanConfig, beanInstance);
  10.  
  11. return beanConfig;
  12. }

  

注册bean实例到Kernel.beanInstances中,bean中所依赖inject的类型,注册到dependencyManager.beanConfigs中,beanConfig通过state来区分,是否为初始化完成的实例

  1. protected BeanConfig Kernel.registerBean(BeanConfig beanConfig, BeanConfig factoryBeanConfig, Object beanInstance) {
  2. BeanConfig parent = null;
  3. if (beanConfig.getSource() == BeanConfig.Source.annotation && !beanConfig.getRegisteredBy().isEmpty()) {
  4. BeanConfig bc = dependencyManager.getBeanConfig(beanConfig.getBeanName());
  5. parent = beanConfig.getRegisteredBy().iterator().next();
  6. if (bc != null && bc.getClazz().equals(beanConfig.getClazz())) {
  7. bc.addRegisteredBy(parent);
  8. parent.addRegisteredBean(bc);
  9. currentlyUsedConfigBuilder = null;
  10. return bc;
  11. }
  12. }
  13.  
  14. if (factoryBeanConfig != null) {
  15. factoryBeanConfig.setPinned(beanConfig.isPinned());
  16. factoryBeanConfig.setState(beanConfig.getState());
  17. unregisterInt(factoryBeanConfig.getBeanName());
  18. dependencyManager.register(factoryBeanConfig);
  19. }
  20.  
  21. BeanConfig oldBeanConfig = dependencyManager.getBeanConfig(beanConfig.getBeanName());
  22. Collection<Dependency> oldDeps =
  23. oldBeanConfig == null ? null : dependencyManager.getDependenciesTo(oldBeanConfig);
  24.  
  25. unregisterInt(beanConfig.getBeanName());
  26. //注册进依赖管理类
  27. dependencyManager.register(beanConfig);
  28. if (parent != null) {
  29. parent.addRegisteredBean(beanConfig);
  30. }
  31. //当实例对象不为空,则更新bean的状态为initialized
  32. if (beanInstance != null) {
  33. putBeanInstance(beanConfig, beanInstance);
  34. beanConfig.setState(State.initialized);
  35. }
  36. //查找出本bean可以注入的被依赖集合,简单地说是B 对象内有个依赖注入的A属性,现在beanConfig为A实现类,此时这里就可以查找出B对象这个依赖项包装类Dependency
  37. Collection<Dependency> deps = dependencyManager.getDependenciesTo(beanConfig);
  38. if (oldDeps != null) {
  39. deps.addAll(oldDeps.stream().filter(od -> {
  40. Field f = od.getField();
  41. return !deps.stream().anyMatch(nd -> nd.getField().equals(f));
  42. }).collect(Collectors.toSet()));
  43. }
  44.  
  45. currentlyUsedConfigBuilder = null;
  46. //如果此函数在所在的本地线程内有延迟注入队列,则加入队列,在finishDependecyDelayedInjection(queue);进行给依赖本beanConfig类型的对象,进行依赖注入
  47. if (!queueForDelayedDependencyInjection(deps)) {
    //当本地线程内无延迟注入队列则为依赖本beanConfig类的对象立即执行依赖注入
  48. injectDependencies(deps);
  49. }
  50.  
  51. return beanConfig;
  52. }

  前面,我们在 initBean(BeanConfig tmpBC, Set<BeanConfig> createdBeansConfig, int deep) 中有看到 beanConfig.getKernel().finishDependecyDelayedInjection(queue);关于赋值就是在这里进行

  1. private boolean queueForDelayedDependencyInjection(Collection<Dependency> deps) {
  2. //本地线程队列存在的时候,才会放到队列里去,后面再进行注入
  3. DelayedDependencyInjectionQueue queue = DELAYED_DEPENDENCY_INJECTION.get();
  4. if (queue == null) {
  5. return false;
  6. }
  7.  
  8. if (deps.isEmpty()) {
  9. return true;
  10. }
  11.  
  12. queue.offer(new DelayedDependenciesInjection(deps));
  13. return true;
  14. }

  

2.举个例子进一步说明下,如MessageRouter中依赖注入componentsAll字段,

  1. @Inject
  2. private Set<ServerComponent> componentsAll;

  

当调用initBean时,程序针对 componentsAll字段进行依赖注入,当xxx字段有提供setXxx() 的函数时,系统会自动调用该函数。如MessageRouter中提供 setComponentsAll(Set<ServerComponent> components) 函数,所以,当注入componentsAll字段时,会自动调用setComponentsAll函数

例如在 MessageRouter 需要注入 componentsAll 组件集合对象,就是在getInstance()时触发的操作

  1. @Bean(name = "message-router", parent = Kernel.class, active = true)
  2. public class MessageRouter ..{
  3. @Inject
  4. private Set<ServerComponent> componentsAll;
  5.  
  6. public void setComponentsAll(Set<ServerComponent> components) {
  7. if (components == null) {
  8. return;
  9. }
  10.  
  11. HashSet<ServerComponent> removeComponents = new HashSet<>(this.components.values());
  12. removeComponents.removeAll(components);
  13. for (ServerComponent comp : removeComponents) {
  14. if (comp instanceof ComponentRegistrator) {
  15. removeRegistrator((ComponentRegistrator) comp);
  16. } else if (comp instanceof MessageReceiver) {
  17. removeRouter((MessageReceiver) comp);
  18. } else {
  19. removeComponent(comp);
  20. }
  21. if (comp instanceof ConnectionManager) {
  22. connectionManagerNames.remove(comp.getName());
  23. }
  24. comp.release();
  25. }
  26.  
  27. HashSet<ServerComponent> newComponents = new HashSet<>(components);
  28. newComponents.removeAll(this.components.values());
    //这里加载到的组件进行相互注册,通知,和7版本的逻辑是一样的,可以去看以前的文章
  29. for (ServerComponent comp : newComponents) {
  30. try {
  31. if (comp instanceof MessageReceiver) {
  32. MessageReceiver mr = (MessageReceiver) comp;
  33. mr.setParent(this);
  34. mr.start();
  35. }
  36. if (comp instanceof ConnectionManager) {
  37. connectionManagerNames.add(comp.getName());
  38. }
  39. if (comp instanceof ComponentRegistrator) {
  40. addRegistrator((ComponentRegistrator) comp);
  41. } else if (comp instanceof MessageReceiver) {
  42. addRouter((MessageReceiver) comp);
  43. } else {
  44. addComponent(comp);
  45. }
  46. } catch (ConfigurationException ex) {
  47. // TODO - most likely this will no longer happen as configuration will not be done in this method
  48. log.log(Level.WARNING, "component " + comp.getName() + " was not configured properly", ex);
  49. }
  50. }
  51. }
  52.  
  53. }

  

三、最终调用 MessageRouter.start() 启动路由组件进行,路由功能,和7版本的原理是一样,这里就不再一一说明,可以找回以前的文章看

到这里启动篇就完成了,Tigase8,看起来代码结构改动大,但是其实也没有多大的变化,核心没有变,变是的包装的架子,所以只要认真地看问题不大,在看源码的同学,建议在调试的时候,再来看这个文章,这样帮助会大些,可以尽可能快地理解Tigase的原理。

如有不对的地方,请提出来,我进行改进!

Tigase8.0 源代码分析:一、启动篇的更多相关文章

  1. Tomcat7.0源代码分析——启动与停止服务原理

    前言 熟悉Tomcat的project师们.肯定都知道Tomcat是怎样启动与停止的. 对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处 ...

  2. Appium Android Bootstrap源代码分析之启动执行

    通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...

  3. Monkey源代码分析番外篇之Android注入事件的三种方法比較

    原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV 往下分析 ...

  4. MonkeyRunner源代码分析之启动

    在工作中由于要追求完毕目标的效率,所以很多其它是强调实战.注重招式.关注怎么去用各种框架来实现目的.可是假设一味仅仅是注重招式.缺少对原理这个内功的了解,相信自己非常难对各种框架有更深入的理解. 从几 ...

  5. v87.01 鸿蒙内核源码分析 (内核启动篇) | 从汇编到 main () | 百篇博客分析 OpenHarmony 源码

    本篇关键词:内核重定位.MMU.SVC栈.热启动.内核映射表 内核汇编相关篇为: v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的 v75.03 鸿蒙内核源码分析(汇编基础) | ...

  6. IDEA 上 Tigase8.0 源代码编译运行

    Tigase交流群 :310790965 一些小伙伴们经常问Tigase8 check下来的源代码怎么跑起来,因为我不能及时一 一回答,所以还是写个博文来演示一下吧,一般针对新手而言,老手的话,就跳过 ...

  7. 【Java】【Flume】Flume-NG源代码分析的启动过程(两)

    本节分析配置文件的解析,即PollingPropertiesFileConfigurationProvider.FileWatcherRunnable.run中的eventBus.post(getCo ...

  8. Monkey源代码分析番外篇WindowManager如何出的喷射事件的进程间的安全限制

    在分析monkey源代码时的一些背景知识不明确,例如看到monkey它是用windowmanager的injectKeyEvent的喷射事件时的方法.我发现自己陷入疙瘩,这种方法不仅能够在当前的应用程 ...

  9. Android应用程序进程启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...

随机推荐

  1. 配置samba的流程

    1.关闭防火墙和selinuxservice iptables stopsetenforce 02.配置本地yummount /dev/cdrom /mediacd /etc/yum.repos.dc ...

  2. 再论 ORM

    Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射. ORM 对象关系映射,这样说还是懵. 这里比较难理解的是 关系 —— 即Relationl ,虽然看起 ...

  3. 啊哈算法第四章第三节 层层递进-广度优先搜索 java实现

    package corejava; public class FourThree { static int [][]a=new int[50][50]; static int [][]b=new in ...

  4. CSS设计中的错误大整理!

    如果有人发明时间机器,那应该将这些错误纠正,不然可把前端程序猿们给还惨了.大家一起看看都有哪些CSS规则应该完善. (CSS 代码) white-space: nowrap 应该 white-spac ...

  5. js验证对象类型

    js验证对象类型 1. Object.prototype.toString.call() 这是最佳解决方案,可以用作通用方式处理.各种类型的判断依据类似于[object Object],替换的是后边的 ...

  6. <mvc:resources mapping="/xxx/**" location="/xxx/"/>无效,可能和Controller的URL模式有关

    某项目webapp下有子目录res,其中有img.css.js等存放静态资源的文件夹. 在定义了dispacher-servlet的<url-pattern>/</url-patte ...

  7. gitkraken clone报错 Configured SSH key is invalid

    gitkraken clone远程仓库时报错 Configured SSH key is invalid. Please confirm that is properly associated wit ...

  8. React Native: unable to load scripts from assets 'index.android.bundle' on real device

    问题:重新建了一个项目后,运行react-native run-android报: unable to load scripts from assets 'index.android.bundle' ...

  9. Java中获取系统时间的四种方式

    第一种: Date day=new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" ...

  10. install django采坑

    1. install python 3 2. install pip 3.  install virtual enviroment : python -m venv myvenv 4. 切换到virt ...