NamedContextFactory 的核心方法是 public <T> T getInstance(String name, Class<T> type),通过这个方法获取 NamedContextFactory 里面的子 ApplicationContext 里面的 Bean。源码是:
NamedContextFactory.java
/** * 获取某个 name 的 ApplicationContext 里面的某个类型的 Bean * @param name 子 ApplicationContext 名称 * @param type 类型 * @param <T> Bean 类型 * @return Bean */ public <T> T getInstance(String name, Class<T> type) { //获取或者创建对应名称的 ApplicationContext AnnotationConfigApplicationContext context = getContext(name); try { //从对应的 ApplicationContext 获取 Bean,如果不存在则会抛出 NoSuchBeanDefinitionException return context.getBean(type); } catch (NoSuchBeanDefinitionException e) { //忽略 NoSuchBeanDefinitionException } //没找到就返回 null return null; } protected AnnotationConfigApplicationContext getContext(String name) { //如果 map 中不存在,则创建 if (!this.contexts.containsKey(name)) { //防止并发创建多个 synchronized (this.contexts) { //再次判断,防止有多个等待锁 if (!this.contexts.containsKey(name)) { this.contexts.put(name, createContext(name)); } } } return this.contexts.get(name); } //根据名称创建对应的 context protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //如果 configurations 中有对应名称的配置类,则注册之 if (this.configurations.containsKey(name)) { for (Class<?> configuration : this.configurations.get(name).getConfiguration()) { context.register(configuration); } } //如果 configurations 中有名称开头为 default. 的配置类,则注册之 for (Map.Entry<String, C> entry : this.configurations.entrySet()) { if (entry.getKey().startsWith("default.")) { for (Class<?> configuration : entry.getValue().getConfiguration()) { context.register(configuration); } } } //注册 PropertyPlaceholderAutoConfiguration,这样可以解析 spring boot 相关的 application 配置 //注册默认的配置类 defaultConfigType context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); //将当前 context 的名称,放入对应的属性中,在配置类中可能会用到 //我们上面举得例子,就是通过 environment.getProperty() 获取了这个属性 context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName, Collections.<String, Object>singletonMap(this.propertyName, name))); if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); //spring boot 可以打包成一种 fatjar 的形式,将依赖的 jar 包都打入同一个 jar 包中 //fatjar 中的依赖,通过默认的类加载器是加载不正确的,需要通过定制的类加载器 //由于 JDK 11 LTS 相对于 JDK 8 LTS 多了模块化,通过 ClassUtils.getDefaultClassLoader() 有所不同 //在 JDK 8 中获取的就是定制的类加载器,JDK 11 中获取的是默认的类加载器,这样会有问题 //所以,这里需要手动设置当前 context 的类加载器为父 context 的类加载器 context.setClassLoader(this.parent.getClassLoader()); } //生成展示名称 context.setDisplayName(generateDisplayName(name)); context.refresh(); return context; }我们这一节详细分析了 Spring Cloud 的基础 NamedContextFactory,搞清楚了其中的原理,并且举了一个简单的例子。接下来我们会详细分析下如何使用以及分析改造一个 Spring Cloud 组件。
微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer: