Spring框架探秘:XML配置文件和解析原理和Bean的实例化方式

Spring的XML解析原理

  • Spring的作用:

    • 定位: 寻找XML配置文件
    • 加载: 将解析的XML配置加载到内存
    • 实例化: 根据加载的XML配置进行实例化
  • IOC体系图:

    • 所有的IOC都有继承关系,这样设计使得任何一个子类IOC都可以直接使用父类IOC加载的Bean
    • 其中重要的类是BeanFactoryApplicationContext,这是所有IOC的父接口
      • BeanFactory中提供了对于Bean最基本的操作
      • ApplicationContext继承BeanFactory, 同时继承MessageSource, ResourceLoader, ApplicationEventPublisher接口用来提供国际化,资源加载,时间发布高级功能 .Spring加载的XML的类是ApplicationContext的子类
    • 其余重要的类:
      • BeanFactory
        • HierarchicalBeanFactory
        • ListableBeanFactory
          • DefaultListableBeanFactory
        • AliasRegistry
          • SimpleAliasRegistry
      • ResourceLoader
        • ApplicationContext
          • AbstractApplicationContext
            • AbstractRefreshableApplicationContext
              • AbstractRefreshableConfigApplicationContext
                • AbstractXmlApplicationContext
                  • ClassPathXmlApplicationContext
  • Spring中的两种标签: 标签在使用前都需要在Springxml配置文件里声明Namespace URI, 这样才能在解析标签时通过Namespace URI找到对应的NamespaceHandler

    • Spring原生标签: 不带前缀的标签是Spring中的原生标签
    • 自定义标签: 带前缀的标签是自定义标签

  • c: 通过构造器给属性赋值,是constructor-arg的简化写法
  • p: 通过属性的setter方法给属性赋值,是property的简化写法
  • Spring自定义扩展标签:
    • 创建一个自定义标签和解析类
    • 指定命名空间和NamespaceHandler
    • META-INFspring.handler文件中指定命名空间和NamespaceHandler的映射关系. 类似Springc标签和p标签一样
  • Spring的XML解析流程:

Spring的Bean实例化原理

  • BeanFactoryPostProcessor的类图:
  • ConfigurationClassPostProcessor类完成对 @Configuration, @Bean等注解的解析注册

Beans

接口实例化

基本概念

  • JavaBean:
    • JavaBean是遵循Sun制定的JavaBean标准的特定编码规范的类:
      • 包含一个默认的公有无参构造器
      • 允许通过gettersetter访问器访问类的成员属性,或者其余遵循特定命名规范的方法访问
      • 实现了java.io.Serializable接口,可序列化
  • POJO:
    • POJO即简单Java对象
    • POJO类的对象不需要通过框架来使用,也不需要在特定的应用服务环境下运行
    • POJO主要用来区分简单Java对象,轻量级Java对象和重量级Java对象
  • SpringBean:
    • SpringBean表示由Spring框架管理的对象,也就是由Spring框架的容器进行初始化,配置和管理的Java对象
    • Spring Bean是通过Spring配置文件或者通过注解定义的,在Spring容器中初始化,然后注入到应用程序中

Spring实例化Bean

  • Spring寻找并解析Bean属性的方式:
    • 注解的方式:
      • Spring在启动后进行初始化时会扫描classpath包下符合要求的class
      • 然后进行解析并注册到BeanFactory
    • xml的方式:
      • 注解通过XmlBeanDefinitionReader解析Bean
    • 一般情况下,主流的方式是使用注解的配置,尤其是在SpringBoot框架中

构造器实例化

  • SpringBean类中的默认构造器创建Bean实例:
    • Spring容器根据Spring配置文件的路径加载配置文件
    • 在加载的同时 ,Spring容器会通过实现Bean类中默认的无参构造器对Bean进行实例化
  • SpringBean构造器实例化示例

静态工厂实例化

  • 工厂实现类中提供一个静态工厂方法创建Bean实例:
    • Spring容器根据Spring配置文件的路径加载配置文件
    • 在加载的同时 ,Spring容器会通过工厂实现类StaticFactoryBean类中的静态方法getBean()Bean进行实例化
  • SpringBean静态工厂实例化示例

实例工厂实例化

  • 工厂实现类直接使用成员方法创建Bean实例,同时在配置文件中:
    • 需要实例化的Bean不是通过class属性直接指向实例化的类
    • 而是通过class属性配置实例工厂
    • 然后通过factory-bean属性指定一个实例工厂
    • 最后使用factory-method属性指定使用factory-bean配置的实例工厂中的哪一个方法
      • Spring容器根据Spring配置文件的路径加载配置文件
      • 在加载的同时 ,Spring容器会通过配置的实例工厂类InstanceBeanFactory中的成员getBean()Bean进行实例化
  • SpringBean实例工厂实例化示例

代理Bean操作

  • 实现一个动态代理接口,并且在Spring容器初始化完成之前将该代理对象注册到Spring容器中.实现可以通过 @Autowired等方法从Spring中获取该代理对象
  • Spring中代理Bean操作示例

Spring中动态注入和删除Bean

  • 动态注入和删除Bean:
    • 使用getBean() 获取对象的操作,这些对象都是程序中事先定义好的
    • 有时候需要动态地加入和删除对象. 尽管可以采用配置文件或者注解的方式,但是每次都需要重启服务
    • 为了避免以上问题,需要在Spring中对Bean进行动态地管理,包括Bean对象的注入和删除
  • Spring中动态管理Bean实现思路:
    • Spring中管理Bean对象的是BeanFactory, 具体的是DefaultListableBeanFactory
      • 通过获取到Bean类的ApplicationContext对象获取到BeanFactory
    • 在类DefaultListableBeanFactory中有registerBeanDefinition() 方法使用一个BeanDefinition参数注入Bean
      • 通过BeanDefinitionBuilder可以构建一个Bean类的BeanDefinition
  • Spring中动态注入Bean步骤:
    • 获取Bean类的ApplicationContext
    • 通过ApplicationContext获取BeanFactory
    • 通过BeanDefinitionBuilder获取Bean类的BeanDefinition
    • 通过BeanFactoryregisterBeanDefinition() 注入Bean类的BeanDefinition
    • 注入完成后,可以通过ApplicationContextgetBean() 获取Bean对象
// 1. 获取Bean类的ApplicationContext
ApplicationContext ctx = SpringApplication.run(Bean.class, args);
// 2. 通过ApplicationContext获取BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
// 3. 获取并创建BeanDefinition
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Bean.class);
beanDefinitionBuilder.addPropertyValue("name", "Oxford"); 
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 4. 通过BeanFactory的registerBeanDefinition()注入Bean类的BeanDefinition
defaultListableBeanFactory.registerBeanDefinition("beanInterface", beanDefinition);
// 获取动态注册的Bean
Bean beanInterface = ctx.getBean(Bean.class);
  • Spring中动态删除Bean步骤:
    • 获取Bean类的ApplicationContext
    • 通过ApplicationContext获取BeanFactory
    • 通过BeanFactoryremoveBeanDefinition() 删除已经注入的Bean类的BeanDefinition
// 1. 获取Bean类的ApplicationContext
ApplicationContext ctx = SpringApplication.run(Bean.class, args);
// 2. 通过ApplicationContext获取BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
// 通过BeanFactory的removeBeanDefinition()删除已经注入的BeanDefinition
defaultListableBeanFactory.removeBeanDefinition("beanInterface");
  • 动态注入Bean出现的问题:
    • 多次注入同一个Bean类时,如果BeanName一样,后注入的Bean会覆盖先注入的Bean
    • 多次注入同一个Bean类时,如果BeanName不一样,就会产生两个Bean
      • 此时不能使用ApplicationContext.getBean(Bean.class) 方法通过ByType方式获取注入的Bean, 会产生报错
      • 此时可以使用ApplicationContext.getBean("beanInterface") 方法通过ByName的方式获取重复注入的Bean
    • 可以使用以下单例方式解决重复注入Bean的问题:
    // 使得Bean对象完成Spring初始化过程中的所有增强器检验,但是不重新创建Bean对象
    applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(beanClass, beanClass.getClass().getName());
    // 将Bean对象以单例的形式注入到容器中. 此时通过 beanClass.getClass() 和 beanClass.getClass().getName() 都可以获取到Spring容器中注入的Bean对象
    defaultListableBeanFactory.registerSingleton(beanClass.getClass().getName(), beanClass);
    

你可能感兴趣的:(Spring框架探秘:XML配置文件和解析原理和Bean的实例化方式)