文章目录
spring核心概念
spring中的几个核心概念,在看源码前先了解这些概念,后面再去看源码会更容易理解源码。
1. beanDefinition
bean的抽象对象,它存储着一个bean对象的各种信息,如class信息、beanName、作用范围scope等信息;spring启动时,会扫描class字节码文件,然后将这些类都存储为beanDefinition,第一次扫描之后,得到所有的bean定义,之后就开始bean的初始化等等操作,所以可以把beanDefinition理解为原材料,spring为包工头,用这些原材料创建,重组完成项目基础架构的建造,所谓兵马未动粮草先行,在spring初始化容器创建bean时,就是根据这些beanDefinition进行实例化的。
定义bean的方式:
<bean/>
- @Bean
- @Component/@Service/@Controller…
使用上面的方式去定义一个bean时,实际上底层spring是有去做解析,并生成beanDefinition这个对象,之后再通过这个对象生成对应的实例化对象,并不会直接生成一个实例化对象,这个联系之后的篇章会更好理解,这里只对概念进行说明。
那么我们指定spring是实例化对象是通过beanDefinition来创建的,所以,我们也可以手动创建一个beanDefinition,然后让spring生成一个,如下代码:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 定义一个beanDefinition,实际类型为MenuService,并且是单例对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(MenuService.class);
beanDefinition.setScope("singleton");
// 将自定义的beanDefinition注册到容器中
applicationContext.registerBeanDefinition("MenuService", beanDefinition);
// 通过getBean获取我们定义的类型的实例对象,这个方法在获取实例对象时,如果没有这个对象,就会创建
MenuService bean = applicationContext.getBean(MenuService.class);
// 打印该对象的内存地址
System.out.println(bean);
2. beanDefinitionReader
beanDefinition的读取器,用于注册beanDefinition, 提供了注册、获取资源加载器、获取类加载器、beanname生成、加载beanDefinition等接口。
对应eanDefinition定义方式,它也有2种读取方式:
XmlBeanDefinitionReader
:扫描<bean/>
标签AnnotatedBeanDefinitionReader
:扫描由注解定义的类,能够解析的注解:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
还有一个读取方式,就是ClassPathBeanDefinitionScanner
,和上面两个一样,多了一个路径扫描,并将扫描到的含有注解的类注册
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 扫描xml注册bean
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beanFactory);
int i = xmlReader.loadBeanDefinitions("spring.xml");
Object userService = beanFactory.getBean("userService");
System.out.println(userService);
// 扫描配置类 注册bean
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(applicationContext);
reader.register(MenuService.class);
MenuService bean = applicationContext.getBean(MenuService.class);
System.out.println(bean);
// 扫描类路径 注册
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
int scan = scanner.scan("com.lry.service");
Object userService2 = beanFactory.getBean("userService");
System.out.println(userService2);
3. beanFactory
beanFactory有存放bean,生成bean的功能,但它只是一个接口,spring中最核心的是DefaultListableBeanFactory
,它是beanFactory最底层的类,获取beanDefinition、注册beanDefinition、别名功能、bean注册、获取bean、自动装配功能等等,也就是管理bean的容器。
如下图,每一个接口都表示着它所拥有的能力:
- AliasRegistry:支持别名功能,一个名字可以对应多个别名
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
- BeanFactory:Bean工厂,可以根据某个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的功能很强大
4. ApplicationContext
首先ApplicationContext
不止继承了beanFactory,还有registry、resourceLoader等,可以完成资源加载、解析、注册bean、获取bean等功能。
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
- MessageSource:拥有国际化功能
5. AnnotationConfigApplicationContext
-
ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
-
AbstractApplicationContext:实现了ConfigurableApplicationContext接口
-
GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
-
AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的**@Configuration注解**,已经可以处理**@Bean注解**),同时可以扫描
-
AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能
-
AutoCloseable:资源关闭
-
Lifecycle:回调类
6. ClassPathXmlApplicationContext
这个功能比起AnnotationConfigApplicationContext
没有注册beanDefinition功能。
![](https://gitee.com/LIRUIYI/typora/raw/master/images/image-20210228104110403.png)
7. 国际化
可配置国际通用的配置,配置格式:文件基础名称_语言.properties
// 这种文件基础名称
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
// 设置基础名称
messageSource.setBasename("message");
// 需要加上这个编码,不然读出来的是乱码(编码根据文件的编码格式设置)
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
return messageSource;
}
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 通过key或对应信息
// 这里的Locale设置语言,有提供默认的,也可以自己设置:new Locale("文件后缀")
String message = applicationContext.getMessage("key", null, Locale.ENGLISH);
System.out.println(message);
System.out.println(applicationContext.getMessage("key", null, Locale.CHINESE));;
上述代码读取的文件是/resource/message_zh_ch.properties
,是在resource下的,没有文件夹;
当然,文件命名不会这么死板的叫zh_ch
,也可以是其他的,如message_zhong.properties
,都是可以设置的:
System.out.println(applicationContext.getMessage("key", null, new Locale("zhong")));;
8. 资源加载
Resource resource = applicationContext.getResource("spring.xml");
System.out.println(resource.getFilename());
System.out.println(applicationContext.getResource("file:E:\\Program File\\work\\workspace\\other_people\\spring-framework2\\luban\\src\\main\\java\\com\\lry"));
9. 运行时环境
可以做到如下的操作
// 获取JVM所允许的操作系统的环境
annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();
// 获取JVM本身的一些属性,包括-D所设置的
annotationConfigApplicationContext.getEnvironment().getSystemProperties();
// 还可以直接获取某个环境或properties文件中的属性
annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")
@Component
@ConfigurationProperties(prefix = "test")
@PropertySource(value = {"classpath:pro.properties"})
//@PropertySource(value = {"file:E:/pro.properties"})
public class TestClass {
@Value("${test.name}")
private String name;
@Value("${test.age}")
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
10. 事件发布
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}
applicationContext.publishEvent("ss");
这里出现两次打印,是因为在spring启动完后会有一次,然后我手动调用一次,一共两次
![image-20210228134451765](https://gitee.com/LIRUIYI/typora/raw/master/images/image-20210228134451765.png)
11. 类型转化
PropertyEditor
jdk提供的工具类,PropertyEditor
看名字就知道,将spring转化为对象
public class CustomPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
user.setName(text);
this.setValue(user);
}
}
继承了PropertyEditorSupport
CustomPropertyEditor editor = new CustomPropertyEditor();
editor.setAsText("测试");
Object value = editor.getValue();
System.out.println(((User)value).getName());
![](https://gitee.com/LIRUIYI/typora/raw/master/images/image-20210228140334604.png)
ConversionService
对比PropertyEditor
,功能更多
public class CustomConvertor 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("ceshi");
return user;
}
}
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new CustomConvertor());
User ceshi = conversionService.convert("ceshi", User.class);
System.out.println(ceshi.getName());
TypeConverter
这个转换器整合了PropertyEditor
和ConversionService
的功能
// 将value转化为requiredType类型
convertIfNecessary(Object value, Class<T> requiredType)
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new CustomPropertyEditor());
User user = typeConverter.convertIfNecessary("ceshi", User.class);
System.out.println(user.getName());
12. BeanPostProcessor
bean的后置处理器,可以在创建每个Bean的过程中进行干涉,如在bean的实例化前或后,修改bean,或者做一些处理,如aop
13. BeanFactoryPostProcessor
bean工厂的后置处理器,可以对beanFactory继续设置,比如修改beanFactory的属性,增加xml方式注入的忽略接口等。
14. FactoryBean
它和beanFactory不一样,首先factoryBean可以注册成为一个bean,而它的子类更是添加了获取bean工厂的接口,如AbstractFactoryBean
,继承子类你就有了bean工厂的功能。
理解的话,有点像工厂模式,用于生产某个bean的,它的getObject方法只调用一次。