Spring之底层架构核心概念解析

84 阅读4分钟

之前大致了解了Spring中的一些概念和底层工作流程,本章对这些概念进行更深入的了解。

BeanDefinition

Bean的定义,存在很多属性用来描述Bean一个Bean的特点,比如:

  • class-----表示Bean的类型
  • scope----表示Bean的作用域,是否是懒加载,单例或者原型
  • lazyInit---表示Bean是否时懒加载
  • initMethodName---Bean初始化时需要执行的方法
  • destoryMethodName ----Bean销毁时奥执行的方法
  • 还有很多......

在spring中,我们经常通过以下方式来定义bean:

  1. @Bean
  2. @Component(@Service,@Controller)

这些我们称之为申明式定义bean,我们还可以编程式定义bean,那就是直接通过BeanDefinition,比如:

//注解配置应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class); 
//生成一个BeanDefination对象,并设置beanclass为User.class-----对象所属的类为User类,并注册到ApplicationContext中
AbstractBeanDefinition  beanDefinition = 
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);

context,registryBeanDefinition("user",beanDefinition);
System.out.println(context.getBean("user"));

Builder(图纸,根据图纸生产bean)-----generic(生产bean)----get(使用bean)

可以通过Beandefinition设置bean的其他属性: 比如设置Bean的作用域,bean的初始化方法,bean是否懒加载。

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载

和申明式事务、编程式事务类似,通过,@Bean,@Component等申明式方式所定义的
Bean,最终都会被Spring解析为对应的BeanDefinition对象,并放入Spring容器中。

BeanDefinitionReader

BeanDefinition读取器---开发中用的少但是是Spring源码的基础设施:

  1. AnntatedBeanDefinitionReader

可以直接把某个类转化为Beandefinition,并且会解析该类上的注解,注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、
@Role、@Description😊😊

  1. XMlBeanDefinitionReader

可以解析Bean标签

  1. ClassPathBeanDefinitionScanner

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

BeanFactory

创建Bean,表示Bean的工厂,负责创建Bean,并且提供获取Bean的API,而ApplicationContext是BeanFactory的一种。 在源码中是这么定义的:

public interface ApplicationContext extends EviromentCapable,ListableBeanFactory,
HierarchicalBeanFactory,MessageSourcce,
ApplicationEnventPublisher,ResourcePatterResolver{
...
}

首先,在Java中,接口是可以多继承的,我们发现ApplicationContext继承了ListableBeanFactory
和HierarchicalBeanFactory,而ListableBeanFactory和HierarchicalBeanFactory都继承至
BeanFactory,所以我们可以认为ApplicationContext继承了BeanFactory,相当于苹果继承水果,
宝马继承汽车一样,ApplicationContext也是BeanFactory的一种,拥有BeanFactory支持的所有功
能,不过ApplicationContext比BeanFactory更加强大,ApplicationContext还基础了其他接口,也
就表示ApplicationContext还拥有其他功能,比如MessageSource表示国际化,
ApplicationEventPublisher表示事件发布,EnvironmentCapable表示获取环境变量,等等,关于
ApplicationContext后面再详细讨论。
在Spring的源码实现中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory出
来,去创建Bean,当使用ApplicationContext的某些方法时,比如getBean(),底层调用的是BeanFactory的
getBean()方法,想办法去获得一个Bean。

在Spring源码中,BeanFacotry有一个非常重要的实现类:DefaultListableBeanFactory,也是非常核心的 , 所以,我们可以直接来使用DefaultListableBeanFactory,而不用使用ApplicationContext的某个 实现类

DefaultListableBeanFactory的功能是非常强大的,支持很多的功能,可以查看它的继承结构图来查看

image.png

ApplicationContext

是一个接口,实际上也是一个BeanFactory,不过比BeanFactory更加强大

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

ApplicationContext有两个重要的实现类:

  1. AnnotationConfigApplicationContext

通过注解配置应用程序上下文

  1. ClassPathXmlApplicationContext

类路径xml应用程序上下文

它也是继承了,AbstractApplicationContext,但是对于AnnotationConfigApplicationContext而言,功能没有注解配置应用程序上下文强大

ApplicationContext拥有的功能

  • 国际化
  • 资源加载
  • 获取运行时环境
  • 事件发布
//可以先定义一个事件监听器
@Bean
public ApplicationListener applicationListner(){
return ApplicationListener(){
@Override
public void onApplicationEvent(ApplicationEvent event){
System.out.println("接收到一个事件!");
}

};

}

然后发布一个事件

context.publishEvent("kkk");

  • 类型转换

在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便 的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。

  • Property Editor

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 CustEditorConfigurer customEditorConfigurer(){
CustEdiorConfigurer customEditorConfigurer = new CustEditorConfigurer();
Map<Class<?>,Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();

// 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前 对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化 

propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); 

customEditorConfigurer.setCustomEditors(propertyEditorMap);
return customEditorConfigurer;
}

}
- ConversionService

Spring内部提供类类型转化服务,他比PropertyEditor(JDK提供的类型转化工具类)功能更加的强大