当前位置: 首页 > wzjs >正文

网站开发背景及意义建行生活网页版登录入口

网站开发背景及意义,建行生活网页版登录入口,推广学校网站怎么做,招聘网最新招聘信息网ApplicationContext实现原理一,对XMl资源文件的解析二,BeanFactoryPostProcess的自动化执行三,BeanPostProcess的自动化执行四,提前初始化单列Bean五,完整代码 上篇:Spring是如何实现PostProcess容器扩展机…

    • ApplicationContext实现原理
      • 一,对XMl资源文件的解析
      • 二,BeanFactoryPostProcess的自动化执行
      • 三,BeanPostProcess的自动化执行
      • 四,提前初始化单列Bean
      • 五,完整代码

上篇:Spring是如何实现PostProcess容器扩展机制

在前面的章节当中我们实现了SpringIOC的基本功能,但是这还不够,可以看一下下面的列子

@Test  
public void testBeanPostPostProcess() {  // 创建默认的BeanFactory实例  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();  // 创建XML Bean定义读取器,并加载指定的Spring配置文件  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");  // 向BeanFactory注册自定义的BeanPostProcessor  factory.addBeanPostProcessor(new CustomerBeanPostProcessor());  // 从BeanFactory中获取名为"people"的Bean实例,并打印其内容  People people = (People) factory.getBean("people");  System.out.println(people);  
}

在这里我们创建了一个BeanFactory对象之后还需要,手动调用方法加载资源文件,同时对于PostProcess也需要我们通过内置方法进行添加,那能否实现自动化的添加就是ApplicationContext要做的事情

ApplicationContext实现原理

其实ApplicationContext的实现与BeanFactory非常类似,都是通过对子类的委托实现功能的拓展。

再说实现ApplicationContext代码之前,我们先想想要做什么,如何实现自动化的对Bean的初始化,要经过哪些步骤

首先我们在初识Spring的时候肯定都了解过一个类ClassPathXmlApplicationContext可以看一下下面的代码

	@Testpublic void testApplicationContext() throws Exception {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");Person person = applicationContext.getBean("person", Person.class);}

我们通过ClassPathXmlApplicationContext这个类的构造函数传入要加载的xml文件从classPath路径,之后我们就可以从容器当中获取到我们的Bean了

那么在整个历程要经过哪些步骤呢

  1. 通过ClassLoader加载xml资源文件,获取到Resource对象,然后将其通过XmlBeanDefinitionReader将里面的标签注册为BeanDefinition。
  2. 执行BeanFactoryPostProcess
  3. 将BeanPostProcess加入到对应的容器当中
  4. 提前初始化Bean

一,对XMl资源文件的解析

在Spring当中对XML文件的加载委托给了XmlBeanDefinitionReader这个类,实际上对于BeanDefinitionReader当中就提供了基本的加载资源文件的接口,其抽象实现AbstractBeanDefinitionReader,对当中的基本逻辑进行了补充。在此之后我们就可以自定义不同文件的加载逻辑去加载为BeanDefinition,值得说一下的是BeanDefinitionReader的加载beanDefinition的方法loadBeanDefinitions在实际外部调用的过程当中传入的是资源文件的ClassPath路径,因此在这里还需要依赖到ResourceLoader去通过解析路径。

上面是对XML文件加载的回顾,经过上述我们也可以明白,要实现自动化的文件加载需要依赖到哪些类,现在我们只需要直接拿出来用即可

来看一下实现逻辑

首先我们得定义好我的ApplicationContext,它也就是一个接口实现逻辑与BeanFactory,都将单一职责的原则贯彻到底,具体的功能拓展都委托给子类

/**  * ApplicationContext 接口是 Spring 框架中的核心接口之一,用于提供应用程序的配置信息。  * 它继承了 ListableBeanFactory、HierarchicalBeanFactory 和 ResourceLoader 接口,  * 从而具备了以下功能:  * 1. 列出所有 Bean 定义的能力(通过 ListableBeanFactory)。  * 2. 支持 Bean 工厂的层次结构(通过 HierarchicalBeanFactory)。  * 3. 加载资源文件的能力(通过 ResourceLoader)。  *  * 该接口通常用于在 Spring 应用程序中获取 Bean 实例、管理 Bean 的生命周期以及加载资源。  */  
public interface ApplicationContext extends ListableBeanFactory , HierarchicalBeanFactory  {  }

ConfigurableApplicationContext实现ApplicationContext的配置化功能

/**  * ConfigurableApplicationContext 接口扩展了 ApplicationContext 接口,提供了对应用上下文配置的支持。  * 该接口允许在应用上下文初始化之前或之后进行配置,例如设置父上下文、刷新上下文等操作。  *  * 实现该接口的类通常用于管理 Spring 应用上下文的生命周期和配置。  *  * @see ApplicationContext */public interface ConfigurableApplicationContext extends ApplicationContext {  /**  * 刷新容器。  * 该方法用于重新加载或更新容器中的内容,通常用于在容器状态发生变化时,  * 确保容器内的数据或配置与当前状态保持一致。  * 该方法不接收任何参数,也不返回任何值。  */  void refresh();  
}

AbstractApplicationContext,在上面的介绍当中也说了,首先我们要做的事情就是解析XML文件初始化Bean,所以我们在AbstractApplicationContext当中的refresh方法当中开始对该逻辑进行实现。但是在这里就还会有一个问题,当前我们的需求是解析XML文件,那如果在后续我们相对其进行拓展我想解析JSON注册Bean怎么办。这里也就是为什么在AbstractApplicationContext当中调用的都是抽象方法,在这里我们实际上就只是定义一个模版,规范解析的步骤,至于具体如何实现就需要根据我们的需求了。这样就可以实现不同解析方式的动态扩展,实现高内聚低耦合。

  
/**  * AbstractApplicationContext 是一个抽象类,实现了 ConfigurableApplicationContext 接口。  * 该类提供了应用程序上下文的基本实现,特别是容器的刷新功能。  *  * @author: jixu * @create: 2025-04-19 14:37 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {  /**  * 刷新容器。  * 该方法用于重新加载或刷新应用程序上下文中的配置和资源。  * 通常用于在运行时动态更新应用程序的配置。  *  * 该方法是一个抽象方法的实现,具体刷新逻辑由子类提供。  */  @Override  public void refresh() {  // 通过子类创建BeanFactory,同时初始化beanDefinition  refreshBeanFactory();  // 获取到Bean工厂  ConfigurableListableBeanFactory beanFactory = getBeanFactory();  }  protected abstract void refreshBeanFactory();  protected abstract ConfigurableListableBeanFactory  getBeanFactory();}

AbstractRefreshableApplicationContext,在实现完AbstractApplicationContext的逻辑后我们发现在refreshBeanFactory也就是初始化Bean的方法当中有些逻辑是共通的,不管我们定义何种解析方法都需要用到这些东西,那么我们就可以在这里进行进一步的抽取。

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{  private ConfigurableListableBeanFactory  beanFactory;  @Override  protected void refreshBeanFactory() {  // 创建Bean  DefaultListableBeanFactory beanFactory = createBeanFactory();  // 加载BeanDefinition  loadBeanDefinitions(beanFactory);  this.beanFactory = beanFactory;  }  protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) ;  private DefaultListableBeanFactory createBeanFactory() {  DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();  return defaultListableBeanFactory;  }  @Override  public ConfigurableListableBeanFactory getBeanFactory() {  return beanFactory;  }  public void setBeanFactory(DefaultListableBeanFactory beanFactory) {  this.beanFactory = beanFactory;  }  }

AbstractXmlApplicationContext现在就来到真正的XML文件的解析逻辑了,可以看到在这里我的定义了一个AbstractXmlApplicationContext,那么是不是也可以定义一个AbstractJSONApplicationContext实现AbstractRefreshableApplicationContext的loadBeanDefinitions方法呢,答案是肯定的。但是只做到这一步还是不够的,我们需要解析XML文件就需要获取到文件的路径,这个路径的获取通过上面的示例也能看出来,是通过构造方法创建的,那我我们就还需要一个用于获取路径的类实现AbstractXmlApplicationContext同时实现获取路径的方法

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{  @Override  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  String[] locations = getConfigLocations();  xmlBeanDefinitionReader.loadBeanDefinitions(locations);  }  // 获取到Classpath下的所有配置资源路径  protected abstract String[] getConfigLocations();  
}

ClassPathApplicationContext

public class ClassPathApplicationContext extends AbstractXmlApplicationContext{  private String[] configLocations;  @Override  protected String[] getConfigLocations() {  return this.configLocations;  }  public ClassPathApplicationContext(String configLocation){  this.configLocations = new String[]{configLocation};  }  public ClassPathApplicationContext(String[] configLocations){  this.configLocations = configLocations;  }  }

到这里我们的第一步对于XML的解析就讲完了,后面应该就是执行BeanPostProcessors与BeanFactoryPostProcess的增强方法了

二,BeanFactoryPostProcess的自动化执行

首先我们先来回顾一下BeanFactoryPostProcess的实现原理,BeanFactoryPostProcessor的实现是基于Spring的一个扩展点ConfigurableListableBeanFactory,在该接口当中我们可以通过其内置的方法getBeanDefinition获取到指定Bean的定义信息之后就可以对其进行修改。除此之外执行增强方法也需要调用有具体子类实现的postProcessBeanFactory方法。

那么现在就会产生一个问题,如何拿到所有已定义的BeanFactoryPostProcess。其实逻辑很简单,获取到所有的BeanFactoryPostProcess,之后循环遍历执行即可。Spring是通过将所有的BeanFactoryPostProcess加入到容器当中,然后从容器获取BeanFactoryPostProcess类型的Bean,来解决这个问题的。

// 执行BeanFactoryPostProcess的方法  
invokeBeanFactoryPostProcessors(beanFactory);
/**  * 执行所有BeanFactoryPostProcessor的postProcessBeanFactory方法。  * 该方法会从BeanFactory中获取所有类型为BeanFactoryPostProcessor的Bean,并依次调用它们的postProcessBeanFactory方法。  *  * @param beanFactory 可配置的BeanFactory实例  */
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {  // 获取到所有已注册到容器当中的BeanPostProcess  Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeanOfType(BeanFactoryPostProcessor.class);  for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {  beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);  }  
}

三,BeanPostProcess的自动化执行

BeanPostProcess的逻辑与BeanFactoryPostProcess非常类似,只是区别在于BeanPostProcess是对Bean的增强其前置与后置增强方法不需要我们手动调用,在createBean的时候会自动调用这些方法。我们要做的就是将用户已定义的BeanPostProcess加入到对应的BeanPostProcessMap当中。

// 注册BeanPostPostProcess  
registerBeanPostProcessors(beanFactory);
/**  * 注册所有BeanPostProcessor到BeanFactory中。  * 该方法会从BeanFactory中获取所有类型为BeanPostProcessor的Bean,并将它们注册到BeanFactory中。  *  * @param beanFactory 可配置的BeanFactory实例  */  
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {  Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeanOfType(BeanPostProcessor.class);  for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {  beanFactory.addBeanPostProcessor(beanPostProcessor);  }  
}

四,提前初始化单列Bean

preInstantiateSingletons方法是ConfigurableListableBeanFactory提供的,我们在AbstractApplicationContext当中已经继承了该方法,直接调用即可

// 提前初始化单列Bean  
beanFactory.preInstantiateSingletons();

五,完整代码

可参考 https://gitee.com/jixuonline/jixu-mini-spring.git

在这里插入图片描述

ApplicationContext

/**  * ApplicationContext 接口是 Spring 框架中的核心接口之一,用于提供应用程序的配置信息。  * 它继承了 ListableBeanFactory、HierarchicalBeanFactory 和 ResourceLoader 接口,  * 从而具备了以下功能:  * 1. 列出所有 Bean 定义的能力(通过 ListableBeanFactory)。  * 2. 支持 Bean 工厂的层次结构(通过 HierarchicalBeanFactory)。  * 3. 加载资源文件的能力(通过 ResourceLoader)。  *  * 该接口通常用于在 Spring 应用程序中获取 Bean 实例、管理 Bean 的生命周期以及加载资源。  */  
public interface ApplicationContext extends ListableBeanFactory , HierarchicalBeanFactory  {  
}

ConfigurableApplicationContext

/**  * ConfigurableApplicationContext 接口扩展了 ApplicationContext 接口,提供了对应用上下文配置的支持。  * 该接口允许在应用上下文初始化之前或之后进行配置,例如设置父上下文、刷新上下文等操作。  *  * 实现该接口的类通常用于管理 Spring 应用上下文的生命周期和配置。  *  * @see ApplicationContext */public interface ConfigurableApplicationContext extends ApplicationContext {  /**  * 刷新容器。  * 该方法用于重新加载或更新容器中的内容,通常用于在容器状态发生变化时,  * 确保容器内的数据或配置与当前状态保持一致。  * 该方法不接收任何参数,也不返回任何值。  */  void refresh();  
}

AbstractApplicationContext

/**  * AbstractApplicationContext 是一个抽象类,实现了 ConfigurableApplicationContext 接口。  * 该类提供了应用程序上下文的基本实现,特别是容器的刷新功能。  *  * @author: jixu * @create: 2025-04-19 14:37*/public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {  /**  * 刷新容器。  * 该方法用于重新加载或刷新应用程序上下文中的配置和资源。  * 通常用于在运行时动态更新应用程序的配置。  *  * 该方法是一个抽象方法的实现,具体刷新逻辑由子类提供。  */  @Override  public void refresh() {  // 通过子类创建BeanFactory,同时初始化beanDefinition  refreshBeanFactory();  // 获取到Bean工厂  ConfigurableListableBeanFactory beanFactory = getBeanFactory();  // 执行BeanFactoryPostProcess的方法  invokeBeanFactoryPostProcessors(beanFactory);  // 注册BeanPostPostProcess  registerBeanPostProcessors(beanFactory);  // 提前初始化单列Bean  beanFactory.preInstantiateSingletons();  }  /**  * 注册所有BeanPostProcessor到BeanFactory中。  * 该方法会从BeanFactory中获取所有类型为BeanPostProcessor的Bean,并将它们注册到BeanFactory中。  *  * @param beanFactory 可配置的BeanFactory实例  */  private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {  Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeanOfType(BeanPostProcessor.class);  for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {  beanFactory.addBeanPostProcessor(beanPostProcessor);  }  }  /**  * 执行所有BeanFactoryPostProcessor的postProcessBeanFactory方法。  * 该方法会从BeanFactory中获取所有类型为BeanFactoryPostProcessor的Bean,并依次调用它们的postProcessBeanFactory方法。  *  * @param beanFactory 可配置的BeanFactory实例  */  private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {  // 获取到所有已注册到容器当中的BeanPostProcess  Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeanOfType(BeanFactoryPostProcessor.class);  for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {  beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);  }  }  /**  * 刷新BeanFactory。  * 该方法是一个抽象方法,具体实现由子类提供,用于创建或刷新BeanFactory。  */  protected abstract void refreshBeanFactory();  /**  * 获取当前BeanFactory实例。  * 该方法是一个抽象方法,具体实现由子类提供,用于返回当前BeanFactory的实例。  *  * @return 当前BeanFactory的实例  */  protected abstract ConfigurableListableBeanFactory  getBeanFactory();  /**  * 根据指定的类型获取所有符合条件的Bean实例,并以Map形式返回。  * Map的键为Bean的名称,值为对应的Bean实例。  *  * @param type 要查找的Bean类型  * @return 包含所有符合类型条件的Bean实例的Map,键为Bean名称,值为Bean实例  */  @Override  public <T> Map<String, T> getBeanOfType(Class<T> type) {  return getBeanFactory().getBeanOfType(type);  }  /**  * 获取当前BeanFactory中所有Bean定义的名称。  *  * @return 包含所有Bean定义名称的字符串数组  */  @Override  public String[] getBeanDefinitionNames() {  return getBeanFactory().getBeanDefinitionNames();  }  /**  * 根据指定的 Bean 名称获取对应的 Bean 实例。  *  * @param name Bean 的名称,通常是在 Spring 配置文件中定义的 Bean 的 ID 或名称。  * @return 返回与指定名称对应的 Bean 实例。如果找不到对应的 Bean,可能会抛出异常。  */  @Override  public Object getBean(String name) {  return getBeanFactory().getBean(name);  }  
}

AbstractRefreshableApplicationContext

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{  private ConfigurableListableBeanFactory  beanFactory;  @Override  protected void refreshBeanFactory() {  // 创建Bean  DefaultListableBeanFactory beanFactory = createBeanFactory();  // 加载BeanDefinition  loadBeanDefinitions(beanFactory);  this.beanFactory = beanFactory;  }  protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) ;  private DefaultListableBeanFactory createBeanFactory() {  DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();  return defaultListableBeanFactory;  }  @Override  public ConfigurableListableBeanFactory getBeanFactory() {  return beanFactory;  }  public void setBeanFactory(DefaultListableBeanFactory beanFactory) {  this.beanFactory = beanFactory;  }  }

AbstractXmlApplicationContext

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{  @Override  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  String[] locations = getConfigLocations();  xmlBeanDefinitionReader.loadBeanDefinitions(locations);  }  // 获取到Classpath下的所有配置资源路径  protected abstract String[] getConfigLocations();  
}

ClassPathApplicationContext

public class ClassPathApplicationContext extends AbstractXmlApplicationContext{  private String[] configLocations;  @Override  protected String[] getConfigLocations() {  return this.configLocations;  }  public ClassPathApplicationContext(String configLocation){  this.configLocations = new String[]{configLocation};  }  public ClassPathApplicationContext(String[] configLocations){  this.configLocations = configLocations;  }  }

文章转载自:

http://E5Yekx9q.qnbgh.cn
http://cAQIWiPo.qnbgh.cn
http://NOMoZn8J.qnbgh.cn
http://pCidQZcf.qnbgh.cn
http://YHMNmf4y.qnbgh.cn
http://hvKZGrYx.qnbgh.cn
http://s4DbmkPJ.qnbgh.cn
http://o4qY9zlr.qnbgh.cn
http://IXpCunv6.qnbgh.cn
http://HFAbDkT3.qnbgh.cn
http://RIBVYfHB.qnbgh.cn
http://UtybNCOh.qnbgh.cn
http://ZXFHMtSl.qnbgh.cn
http://5N3ZfJqP.qnbgh.cn
http://7qiLKTRk.qnbgh.cn
http://aqdqoYqP.qnbgh.cn
http://2rVAvJ3m.qnbgh.cn
http://ogMGPZ5j.qnbgh.cn
http://XPVBjy7Q.qnbgh.cn
http://UOE7dt9c.qnbgh.cn
http://LM4aGdZz.qnbgh.cn
http://uP91eJRo.qnbgh.cn
http://UWJNeII1.qnbgh.cn
http://mZsakp2B.qnbgh.cn
http://UHDSZ6Gl.qnbgh.cn
http://FDLYxLmp.qnbgh.cn
http://LWNShewq.qnbgh.cn
http://BgHJZoOI.qnbgh.cn
http://eyEYg6Hk.qnbgh.cn
http://1HNbxdyh.qnbgh.cn
http://www.dtcms.com/wzjs/710376.html

相关文章:

  • 南京500元做网站软件科技公司网站模板
  • 怎么用电脑做网站服务器wordpress里网站名称在哪里修改
  • 用pageadmin做的网站用什么虚拟主机号Wordpress修改览量点赞量
  • 做效果图去哪个网站接活网站建设需求策划书
  • 为什么要在南极建站深圳公司注册地址可以是住宅吗
  • 成都哪家公司做网站好wordpress 搜索调用
  • 代挂QQ建设网站可以搜索企业信息的软件
  • 建设银行的网站查询密码洛阳网站建设多少钱
  • 东营建设信息网站电话美图秀秀网页版入口
  • 哪有免费的网站国内做免费的视频网站
  • 网站整合方案网络课程网站建设
  • 门户网站建设哪家好wordpress 4 下载地址
  • 网站维护 费用网站原型图怎么做
  • 网站别人给我做的备案 我能更改吗通州专业网站制作
  • 网站页面设计稿足球比赛直播360
  • 新乡手机网站建设电话如何给网站文字做超链接
  • 网站制作需要什么人员网页设计与制作实训报告实训目的
  • 如何做网站主题淄博网站建设咨询臻动传媒
  • 制作网站专业公司哪家好做网站怎么每天更新内容
  • 高明专业网站建设报价做引流去那些网站好
  • 电商网站建设需求滨海建设局官方网站
  • 索莱宝做网站网页模板下载html
  • 中小企业网站用什么技术交换广告是两个网站做友情链接吗
  • godady怎么做网站wordpress如何添加商桥
  • 快速优化网站排名搜索php网站转移
  • 盐城网站建设厂商东莞做外贸网站
  • 做权重网站网络设计师证怎么考
  • 网站制作app开发公司2013年以前pc网站建设
  • 福州网站建设熊掌号网站建设宝典
  • 网站优化排名怎么做怎么做二维码进网站