Spring核心概念(源码相关)

102 阅读7分钟

本文主要讲解Spring源码中经常看到的类的作用,中间会有会有部分代码讲解,各模块的具体源码会写在后面的文章中

BeanDefinition

BeanDefinition中保存了我们Bean的信息。声名式bean的定义下面三种方式 1. xml配置 2.@Bean 3.@Component spring 在读取bean配置信息后会给bean配置生成对应的BeanDefinition象对象存储类信息供spring生产bean使用。我们也可以直接使用beanDefinition生成一个bean。

    public static void main(String[] args) {
         AnnotationConfigApplicationContext applicationContext = 
                    new AnnotationConfigApplicationContext();
         // 获取beanDefinition对象
         AbstractBeanDefinition beanDefinition = 
                    BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
         // 写入需要生产的bean
         beanDefinition.setBeanClass(People.class);
         // 注册到spring容器中
         applicationContext.registerBeanDefinition("myBean",beanDefinition);
         // 刷新容器
         applicationContext.refresh();
         // 获取bean
         System.out.println(applicationContext.getBean(People.class));
         System.out.println(applicationContext.getBean("myBean"));
    }
     
    //结果
    //spring.bean.People@1ce92674
    //spring.bean.People@1ce92674

BeanDefinitionReader

顾名思义,这个类的作用就是读取类配置。它主有很多实现类,例如XmlBeanDefinitionReader 读取的就是方式配置

XmlBeanDefinitionReader

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
    <bean id="people" class="spring.bean.People"/>
</beans>
    public static void main(String[] args) {
      AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      //创建beanDefinitionReader
      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
      //通过xml文件加载bean到applicationContext 返回值为读取到bean的数量
      int i = beanDefinitionReader.loadBeanDefinitions("applicationContext.xml");
      System.out.println(i);
    }
    //结果
    //1

AnnotatedBeanDefinitionReader

注意:这个类并不是解析被@Bean,@Component注解修饰等类,而是解析需要加载的类的一些配置信息如:@Scope,@Lazy

    @Scope("prototype")
    public class People {
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //创建beanDefinitionReader 
        AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
        //通过xml文件加载bean到applicationContext 返回值为读取到bean的数量
        beanDefinitionReader.registerBean(People.class);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("people"));
        System.out.println(applicationContext.getBean("people"));
    }
    // 结果
    // spring.bean.People@5ae50ce6
    //  spring.bean.People@6f96c77

*People.class设置它的作用范围为原型。从结果上面可看出两次得到的People对象确实是不同的

ClassPathBeanDefinitionScanner

通过包扫描注解解析@Component(@Bean注解不会bei扫描)

package spring.bean;
import org.springframework.stereotype.Component;
@Component
public class People {

}
    public static void main(String[] args) {
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
       ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(applicationContext);
       classPathBeanDefinitionScanner.scan("spring.bean");
       applicationContext.refresh();
       System.out.println(applicationContext.getBean(People.class));
    }
    // 结果
    // spring.bean.People@74fe5c40

BeanFactory

Spring中有很多种BeanFactory,本文以它中比较核心的实现类DefaultListableBeanFactory讲解 DefaultListableBeanFactory实现了很多接口表示拥有很多功能

  • AliasRegistry:支持别名功能,一个名字可以对应多个别名
  • BeanDefinitionRegistry: 可以注册、保存、移除、获取某个BeanDefinition
  • BeanFactory:可以根据bean的名字、类型、别名获取Bean对象
  • SingletonBeanRegistry: 可以直接注册、获取单例bean
  • SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
  • ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
  • HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
  • DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
  • ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  • FactoryBeanRegistrySupport:支持了FactoryBean的功能
  • AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
  • AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
  • ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
  • AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
  • DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大

通过以上分析,我们可以知道,通过DefaultListableBeanFactory我们可以做很多事情

    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.setBeanClass(People.class);
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // 注册BeanDefinition
    beanFactory.registerBeanDefinition("people", beanDefinition);
    // 注册别名
    beanFactory.registerAlias("people", "people1");
    // 注册BeanPostProcessor
    beanFactory.addBeanPostProcessor(new LubanBeanPostProcessor());
    // 获取Bean对象
    System.out.println(beanFactory.getBean("people1"));
    // 根据类型获取beanNames
    System.out.println(beanFactory.getBeanNamesForType(People.class));

ApplicationContext

ApplicationContext是一个接口,可以把它理解成一个特殊的BeanFactory

  • HierarchicalBeanFactory:拥有获取父BeanFactory的功能
  • ListableBeanFactory:拥有获取beanNames的功能
  • ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
  • EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
  • ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
  • MessageSource:拥有国际化功能

下面用两个比较重要的实现类进行讲解

AnnotationConfigApplicationContext

  • ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能。
  • AbstractApplicationContext:实现了ConfigurableApplicationContext接口
  • GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,处理@Bean注解),同时可以扫描。
  • AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能。

ClassPathXmlApplicationContext

它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

国际化

定义一个MessageSource

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        //设置语言配置文件前缀 如messages-en_CN、messages-en
        messageSource.setBasename("messages");
        return messageSource;
    }

使用

    // 输出对应语言配置文件中的信息
    annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))

资源加载

ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容

    
    Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\zzf\\src\\main\\java\\com\\zzf\\entity\\People.java");
    System.out.println(resource.contentLength());

  

classpath获取

    Resource resource = annotationConfigApplicationContext.getResource("classpath:com/zzf/entity/People.class");
    System.out.println(resource.contentLength());

一次性获取多个

    Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/zzf/service/*.class");
    for (Resource resource : resources) {
        System.out.println(resource.contentLength());
    }

获取运行时环境

    // 获取JVM所允许的操作系统的环境
    annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();
    // 获取JVM本身的一些属性,包括-D所设置的
    annotationConfigApplicationContext.getEnvironment().getSystemProperties();
    // 还可以直接获取某个环境或properties文件中的属性
    annotationConfigApplicationContext.getEnvironment().getProperty("xxx")

事件发布

定义一个事件监听器

    @Bean
    public ApplicationListener applicationListener() {
        return new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("接收到了一个事件");
            }
        };
    }

    //  发布事件
    annotationConfigApplicationContext.publishEvent("事件XXX");

发布事件

类型转化

PropertyEditor

JDK中提供的类型转化工具类

    public class StringToPeoplePropertyEditor extends PropertyEditorSupport implements PropertyEditor {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            People people = new People();
            people.setName(text);
            this.setValue(people);
        }
    }
    StringToPeoplePropertyEditor propertyEditor = new StringToPeoplePropertyEditor();
    propertyEditor.setAsText("1");
    People value = (People) propertyEditor.getValue();
    System.out.println(value);

Spring中注册PropertyEditor

        @Bean
        public CustomEditorConfigurer customEditorConfigurer() {
            CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
            Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
            // 添加自定义转化器
            propertyEditorMap.put(People.class, StringToPeoplePropertyEditor.class);
            customEditorConfigurer.setCustomEditors(propertyEditorMap);
            return customEditorConfigurer;
        }
    @Component
    public class PeopleService {
        /*
         *  会把"true"设置为people的name
         */
        @Value("true")
        People test;
    
        public void test() {
            System.out.println(test);
        }
    }

ConversionService

Spring中提供的类型转化服务,它比PropertyEditor更强大

    // 定义转换器
    public class StringToPeopleConverter implements ConditionalGenericConverter {
    
        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return sourceType.getType().equals(String.class) && targetType.getType().equals(People.class);
        }
    
        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(String.class, People.class));
        }
    
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            People people = new People();
            people.setName((String)source);
            return people;
        }
    }
    // 正常使用
    DefaultConversionService conversionService = new DefaultConversionService();
    conversionService.addConverter(new StringToPeopleConverter());
    People value = conversionService.convert("1", People.class);
    System.out.println(value);

Spring 中注入ConversionService

    @Bean
    public ConversionServiceFactoryBean conversionService() {
        ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
        conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToPeopleConverter()));
        return conversionServiceFactoryBean;
    }

TypeConverter

整合了PropertyEditor和ConversionService的功能,Spring内部使用

    SimpleTypeConverter typeConverter = new SimpleTypeConverter();
    typeConverter.registerCustomEditor(People.class, new StringToPeoplePropertyEditor());
    People value = typeConverter.convertIfNecessary("1", People.class);
    System.out.println(value);

BeanPostProcessor

Bean的后置处理器,可以在创建每个Bean的过程中进行干涉,是属于BeanFactory中一个属性,Bean的生命周期文章中详细讲。

BeanFactoryPostProcessor

Bean工厂的后置处理器,是属于ApplicationContext中的一个属性,是ApplicationContext在实例化一个BeanFactory后,可以利用BeanFactoryPostProcessor继续处理BeanFactory。 程序员可以通过BeanFactoryPostProcessor间接的设置BeanFactory,比如上文中的CustomEditorConfigurer就是一个BeanFactoryPostProcessor,我们可以通过它向BeanFactory中添加自定义的PropertyEditor。

FactoryBean

允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean。 那么它和@Bean的区别是什么?因为@Bean也可以自定义一个对象,让这个对象成为一个Bean。 区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。