Spring原理(1)——容器(spring容器提供了哪些功能)

  本篇文章为你整理了Spring原理(1)——容器(spring容器提供了哪些功能)的详细内容,包含有spring容器的概念 spring容器提供了哪些功能 spring容器基本的接口是什么 spring容器涉及到哪两个包 Spring原理(1)——容器,希望能帮助你了解 Spring原理(1)——容器。

  从BeanFactory提供的方法来看,主要是从容器中获取Bean。实际上控制反转,依赖注入以及Bean的生命周期管理,都由它的实现类提供。如下展示了BeanFactory其中一个实现类DefaultListableBeanFactory的继承关系。

  可以看到,它的继承路线上有一个DefaultSingletonBeanRegistry类,这个类我们打开可以看到如下代码段,其中singletonObjects对象正是容器中所有单例对象被保存的地方。

  

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

 

   /** Cache of singleton objects: bean name to bean instance. */

   private final Map String, Object singletonObjects = new ConcurrentHashMap (256); // 保存了所有的单例对象

   /** Cache of singleton factories: bean name to ObjectFactory. */

   private final Map String, ObjectFactory ? singletonFactories = new HashMap (16);

  

 

  ApplicationContext

  ApplicationContext继承自多个接口,因此提供了多种能力,具体提供的能力如下代码所示。

  

@SpringBootApplication

 

  public class SsmpApplication {

   public static void main(String[] args) throws IOException {

   final ConfigurableApplicationContext context = SpringApplication.run(SsmpApplication.class, args);

   // MessageSource接口提供的功能,实现国际化能力

   context.getMessage("hi", null, Locale.CHINA);

   context.getMessage("hi", null, Locale.US);

   // ResourcePatternResolver接口提供的能力,实现读取资源文件的能力

   final Resource[] resources = context.getResources("classpath*:spring.factories");

   // EnvironmentCapable接口提供的能力,实现获取环境参数的能力,可以获取环境变量、配置等

   final String java_home = context.getEnvironment().getProperty("java_home");

   final String port = context.getEnvironment().getProperty("server.port");

   // ApplicationEventPublisher提供的能力,可以发送事件,实现解耦

   context.publishEvent(new MyEvent(context));

   public static class MyEvent extends ApplicationEvent {

   public MyEvent(Object source) {

   super(source);

  

 

  BeanFactory实现

  以下代码的注释中展示了BeanFactory是如何注册Bean的,以及注册后如何进行后处理的。

  点击查看代码

  

package com.leo.ssmp;

 

  import lombok.extern.slf4j.Slf4j;

  import org.springframework.beans.factory.annotation.Autowired;

  import org.springframework.beans.factory.config.BeanDefinition;

  import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

  import org.springframework.beans.factory.config.BeanPostProcessor;

  import org.springframework.beans.factory.support.BeanDefinitionBuilder;

  import org.springframework.beans.factory.support.DefaultListableBeanFactory;

  import org.springframework.boot.autoconfigure.SpringBootApplication;

  import org.springframework.context.annotation.AnnotationConfigUtils;

  import org.springframework.context.annotation.Bean;

  import org.springframework.context.annotation.Configuration;

  import java.util.Collection;

  @SpringBootApplication

  @Slf4j

  public class SsmpApplication {

   public static void main(String[] args) {

   // 将MyConfig类注册到BeanFactory中,由BeanFactory管理Bean的生成,销毁

   DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

   final BeanDefinition configDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyConfig.class)

   .setScope("singleton")

   .getBeanDefinition();

   beanFactory.registerBeanDefinition("config", configDefinition);

   // 向BeanFactory上注册一些后处理器,这些后处理器可以解析@Configuration和@Bean这些注解

   AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

   // BeanFactory后处理器,执行后处理操作,处理@Configuration注解,将bean1和bean2生成出来

   final Collection BeanFactoryPostProcessor beanFactoryPostProcessors = beanFactory.getBeansOfType(

   BeanFactoryPostProcessor.class).values();

   log.info("---------------BeanFactory后处理器------------------");

   beanFactoryPostProcessors.forEach(beanFactoryPostProcessor - log.info(beanFactoryPostProcessor.toString()));

   beanFactoryPostProcessors.forEach(beanFactoryPostProcessor - {

   beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);

   log.info("---------------BeanFactory后处理器------------------");

   // Bean后处理器,针对Bean的生命周期的各个阶段做扩展,例如@Autowired @Resource,

   // 这样才能在生成bean1后,向bean1中注入bean2

   final Collection BeanPostProcessor beanPostProcessors = beanFactory.getBeansOfType(BeanPostProcessor.class)

   .values();

   log.info("----------------Bean后处理器-----------------");

   beanPostProcessors.forEach(beanPostProcessor - log.info(beanPostProcessor.toString()));

   beanPostProcessors.forEach(beanFactory::addBeanPostProcessor);

   log.info("----------------Bean后处理器-----------------");

   log.info("------------------注册的所有Bean定义信息------------------");

   final String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();

   for (String beanDefinitionName : beanDefinitionNames) {

   log.info(beanDefinitionName);

   log.info("------------------注册的所有Bean定义信息------------------");

   final Bean1 bean1 = beanFactory.getBean(Bean1.class);

   log.info(bean1.getBean2().toString());

   @Configuration

   static class MyConfig {

   @Bean

   public Bean1 bean1() {

   return new Bean1();

   @Bean

   public Bean2 bean2() {

   return new Bean2();

   static class Bean1 {

   @Autowired

   private Bean2 bean2;

   public Bean1() {

   log.info("Bean1 construct...");

   public Bean2 getBean2() {

   return bean2;

   static class Bean2 {

   public Bean2() {

   log.info("Bean2 construct");

  

 

  以上代码的运行结果如下:

  点击查看代码

  

10:56:43.379 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.context.annotation.internalConfigurationAnnotationProcessor

 

  10:56:43.395 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.context.event.internalEventListenerProcessor

  10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - ---------------BeanFactory后处理器------------------

  10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.ConfigurationClassPostProcessor@724af044

  10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.EventListenerMethodProcessor@4678c730

  10:56:43.512 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.context.event.internalEventListenerFactory

  10:56:43.513 [main] INFO com.leo.ssmp.SsmpApplication - ---------------BeanFactory后处理器------------------

  10:56:43.513 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.context.annotation.internalAutowiredAnnotationProcessor

  10:56:43.513 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.context.annotation.internalCommonAnnotationProcessor

  10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - ----------------Bean后处理器-----------------

  10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6385cb26

  10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@38364841

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ----------------Bean后处理器-----------------

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ------------------注册的所有Bean定义信息------------------

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - config

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalConfigurationAnnotationProcessor

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalAutowiredAnnotationProcessor

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalCommonAnnotationProcessor

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.internalEventListenerProcessor

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.internalEventListenerFactory

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - bean1

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - bean2

  10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ------------------注册的所有Bean定义信息------------------

  10:56:43.517 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean bean1

  10:56:43.518 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean config

  10:56:43.529 [main] INFO com.leo.ssmp.SsmpApplication - Bean1 construct...

  10:56:43.535 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean bean2

  10:56:43.536 [main] INFO com.leo.ssmp.SsmpApplication - Bean2 construct

  10:56:43.537 [main] INFO com.leo.ssmp.SsmpApplication - com.leo.ssmp.SsmpApplication$Bean2@55040f2f

  Process finished with exit code 0

  

 

  后处理器的执行顺序跟它们之间的排序策略有关,先执行的后处理器会生效。

  ApplicationContext实现

  ClassPathXmlApplicationContext

  首先我们定义一个实体类

  

package com.leo.domain;

 

  import lombok.Data;

  @Data

  public class Book {

   private Integer id;

   private String type;

   private String name;

   private String description;

  

 

  在resources目录下创建b01.xml文件作为Spring的配置文件

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:context="http://www.springframework.org/schema/context"

   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"

   bean id="bean1" /

   /beans

  

 

  通常我们会使用如下方式来启动和加载Spring容器

  

package com.leo;

 

  import org.springframework.beans.factory.support.DefaultListableBeanFactory;

  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

  import org.springframework.boot.autoconfigure.SpringBootApplication;

  import org.springframework.context.support.ClassPathXmlApplicationContext;

  import org.springframework.core.io.ClassPathResource;

  @SpringBootApplication

  public class SpringApplication {

   public static void main(String[] args) {

   final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(

   "b01.xml");

  

 

  其内部实现如果简单的拆开来,可以用如下步骤表示,BeanFactory是真正的容器,我们使用XmlBeanDefinitionReader将xml中定义的bean转化成BeanDefinition并注册到BeanFactory中。

  

package com.leo;

 

  import org.springframework.beans.factory.support.DefaultListableBeanFactory;

  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

  import org.springframework.boot.autoconfigure.SpringBootApplication;

  import org.springframework.core.io.ClassPathResource;

  @SpringBootApplication

  public class SpringApplication {

   public static void main(String[] args) {

   testClasspathXmlApplicationContext();

   private static void testClasspathXmlApplicationContext() {

   DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

   System.out.println("======================= before");

   for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {

   System.out.println(beanDefinitionName);

   XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

   reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));

   System.out.println("======================= after");

   for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {

   System.out.println(beanDefinitionName);

  

 

  以上代码的运行结果如下:

  

======================= before

 

  14:14:13.483 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 6 bean definitions from class path resource [b01.xml]

  ======================= after

  bean1

  

 

  我们会发现这是容器里只有一个Bean,但是当我们用springboot自动配置来启动容器时,会发现即使我们不定义Bean,默认也会加载一些内置的bean。那么Spring是如何加载这些内置的Bean的呢。我们可以在xml文件中加入如下配置:

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:context="http://www.springframework.org/schema/context"

   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"

   bean id="bean1" /

   !--这里开启了各种注解,例如Autowired--

   context:annotation-config/

   /beans

  

 

  这样我们运行上面的代码时打印出来的结果如下:

  

======================= before

 

  14:14:13.483 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 6 bean definitions from class path resource [b01.xml]

  ======================= after

  bean1

  org.springframework.context.annotation.internalConfigurationAnnotationProcessor

  org.springframework.context.annotation.internalAutowiredAnnotationProcessor

  org.springframework.context.annotation.internalCommonAnnotationProcessor

  org.springframework.context.event.internalEventListenerProcessor

  org.springframework.context.event.internalEventListenerFactory

  

 

  可以看到这时已经加载了很多处理注解和事件监听的Bean。

  FileSystemXmlApplicationContext

  基本原理与ClassPathXmlApplicationContext相似,只不过这里改为从文件系统直接读取xml配置。

  AnnotationConfigApplicationContext

  直接通过@Configuration注解的类来加载Bean,这种方法加载Bean时,会默认加载注解处理器这些内置的Bean。同时还会将config类也加载为Bean。

  以上就是Spring原理(1)——容器(spring容器提供了哪些功能)的详细内容,想要了解更多 Spring原理(1)——容器的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: