Spring源码分析(一)核心概念记录

1:BeanDefinition

spring主要是为了管理项目中的类和实例的,我们定义的类几种方式xml,注解,@Bean等在被spring读取到之后Spring内部维护我们定义的类的数据结构就是BeanDefinition,它是一个接口,里面定义类的className,是否是单例,是否是懒加载等等属性。

BeanDefinitionReader:

     AnnotatedBeanDefinitionReader

     可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解

     注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

    

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);

// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);

System.out.println(beanFactory.getBean("user"));

 

     XmlBeanDefinitionReader     

XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

System.out.println(beanFactory.getBean("user"));

 

    ClassPathBeanDefinitionScanner

    这个并不是BeanDefinitionReader,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition

 

 

2:容器的继承体系

 在Spring中我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,它作为Spring容器的顶级接口,这系列容器只实现了容器的基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上增加了许多面向框架的特性,同时对应用环境做了适配。

 AliasRegistry:

 管理别名的接口,实现这个接口可以对容器中的某个Bean进行起别名。还可以判断某个名字是否是别名,列出所有的别名。

SimpleAliasRegistry:

 上面接口的简单实现类。

BeanDefinitionRegistry:

是一个注册器接口,实现这个接口可以向容器里面单独注册Bean,是以BeanDefinition为对象的实例注册进去,GenericApplicationContext,DefaultListableBeanFactory都实现了这个接口。

BeanFactory:

spring顶层容器接口,它只定义了容器的基本功能,从容器中获取bean,bean是否是单例等基本功能。

SingletonBeanRegistry:

向单例对象池注册单例对象,获取一个单例bean,判断一个bean是否为单例等单例相关的操作的接口。

DefaultSingletonBeanRegistry:

上面接口的一个实现类,类里定义了单例对象池:singletonObjects,以及早期单例对象(和循环依赖相关)等和单例对象相关的操作。

HierarchicalBeanFactory:

接口,提供设置获取父子容器的功能,但是当前这个接口里只有只有BeanFactory getParentBeanFactory(); 方法,setParentBeanFactory在子接口 ConfigurableBeanFactory中有定义。

ListableBeanFactory:

接口,直接继承BeanFactory,除了基本的容器功能外,提供了一些列出容器中的相关信息的操作比如,是否包含某个BeanDefinition的定义,得到所有的BeanDefinition的name,根据类型获取BeanName等等操作。

FactoryBeanRegistrySupport:

类,继承了DefaultSingletonBeanRegistry类,是一个factorybean,维护了一个被FactoryBeans创建的单例对象池。

ConfigurableBeanFactory:

接口,继承了HierarchicalBeanFactory, SingletonBeanRegistry,额外提供了一些可以配置BeanFactory的功能,比如 setParentBeanFactory:设置父容器。setBeanClassLoader:设置bean加载的classloader。setConversionService:设置转换器。addBeanPostProcessor:添加后置处理器。等等set方法,如果使用的BeanFactory没有实现这个接口这些set方法设置的内容就是spring默认的了。实现这个接口就是可以自定义。

AbstractBeanFactory:

抽象类,继承了FactoryBeanRegistrySupport,实现了ConfigurableBeanFactory,相关的功能已经实现好了,但是不能自动装配和获取beanNames。

AutowireCapableBeanFactory:

接口,是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配。

AbstractAutowireCapableBeanFactory:

继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能而且可以配置BeanFatcoty,功能也是比较完善的,但是它还没有ListableBeanFactory的功能。

ConfigurableListableBeanFactory:

接口,继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory,所以有了可配置BeanFactory,自动注入,和获取bean相关信息的功能。

DefaultListableBeanFactory:

终极的一个功能很完善的spring容器,继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大。还具有注册的功能。

3:ApplicationContext

ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上增加了许多面向框架的特性,同时对应用环境做了适配.

 

 

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

又两个比较重要的实现类:

  1. AnnotationConfigApplicationContext
  2. ClassPathXmlApplicationContext

 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();
    messageSource.setBasename("messages");
    return messageSource;
}

 

有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。

同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:

annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))

资源加载

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

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

 

你可以想想,如果你不使用ApplicationContext,而是自己来实现这个功能,就比较费时间了。

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

 

还可以一次性获取多个资源:

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

 

这个功能用到了策略模式。

获取运行时环境

// 获取JVM所允许的操作系统的环境
annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();

// 获取JVM本身的一些属性,包括-D所设置的
annotationConfigApplicationContext.getEnvironment().getSystemProperties();

// 还可以直接获取某个环境或properties文件中的属性
annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")

 

还可以利用下面的注解把某个properties文件中的参数添加到运行时环境中

@PropertySource("classpath:application.properties")

 

事件发布

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

然后发布一个事件:

annotationConfigApplicationContext.publishEvent("kkk");

 

类型转换器

在项目中使用默认的类型转换器不能满足要求的时候,可能要自定义类型转换器。比如String转成User对象。

1:PropertyEditor

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

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        User user = new User();
        user.setName(text);
        this.setValue(user);
    }
}
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) 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(User.class, StringToUserPropertyEditor.class);
    customEditorConfigurer.setCustomEditors(propertyEditorMap);
    return customEditorConfigurer;
}

假设现在有如下Bean:

@Component
public class UserService {

    @Value("true")
    User test;

    public void test() {
        System.out.println(test);
    }
}

那么test属性就能正常的完成属性赋值

2:ConversionService

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

public class StringToUserConverter implements ConditionalGenericConverter {

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, User.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        User user = new User();
        user.setName((String)source);
        return user;
    }
}
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);

 

向Spring中注册ConversionService:

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

    return conversionServiceFactoryBean;
}

 

3:TypeConverter

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

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());  //把第一种类型转换器注册进来
//typeConverter.setConversionService(conversionService);   //把第二中类型转换器注册进来   可以设置多个
User value = typeConverter.convertIfNecessary("1", User.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的创建进行高级设置。而BeanFactory是创建很多bean的工厂。

那么它和@Bean的区别是什么?因为@Bean也可以自定义一个对象,让这个对象成为一个Bean。

区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以让它再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。

 接口有一个默认的方法,isSingleton返回true.另外两个方法需要自己实现。

 

这个factorybean可以实现其它接口来获取更多的spring相关的属性,而@Bean方法则不行。

 

而且我们通过application.getBean("myFactoryBean");  得到的是getObject返回的对象,而且根据isSingleton的返回是否为单例。如果要得到MyFactoryBean本身,需要用getBean("&myFactoryBean");

 

 

 

 

 

 

 

 

 

SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()); //typeConverter.setConversionService(conversionService); User value = typeConverter.convertIfNecessary("1", User.class); System.out.println(value);

posted @ 2021-05-07 21:41  蒙恬括  阅读(135)  评论(0编辑  收藏  举报