之前大致了解了Spring中的一些概念和底层工作流程,本章对这些概念进行更深入的了解。
BeanDefinition
Bean的定义,存在很多属性用来描述Bean一个Bean的特点,比如:
- class-----表示Bean的类型
- scope----表示Bean的作用域,是否是懒加载,单例或者原型
- lazyInit---表示Bean是否时懒加载
- initMethodName---Bean初始化时需要执行的方法
- destoryMethodName ----Bean销毁时奥执行的方法
- 还有很多......
在spring中,我们经常通过以下方式来定义bean:
- @Bean
- @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源码的基础设施:
- AnntatedBeanDefinitionReader
可以直接把某个类转化为Beandefinition,并且会解析该类上的注解,注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、
@Role、@Description😊😊
- XMlBeanDefinitionReader
可以解析Bean标签
- 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的功能是非常强大的,支持很多的功能,可以查看它的继承结构图来查看
ApplicationContext
是一个接口,实际上也是一个BeanFactory,不过比BeanFactory更加强大
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能
- MessageSource:拥有国际化功能
ApplicationContext有两个重要的实现类:
- AnnotationConfigApplicationContext
通过注解配置应用程序上下文
- 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提供的类型转化工具类)功能更加的强大