1 BeanDefinition
spring里面一个bean的定义类就是BeanDefinition,在spring中,我们可以如下定义一个Bean:
- @Bean
- @Component(@Service, @Controller)
还有可以通过Spring提供给我们的API的编程式地定义一个BeanDefinition:
private static void beanDefinitionTest() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(AppConfig.class);
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
applicationContext.registerBeanDefinition("appConfig", beanDefinition);
beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); // 设置自动装配模型
// 根据BeanDefinition来产生bean对象
applicationContext.refresh();
System.out.println(applicationContext.getBean("appConfig"));
}
2 BeanDefinitionReader
从名字来看,BeanDefinitionReader就是读取BeanDefinition的工具,BeanDefinition是一个接口,具体的从哪里读取就要看他具体的实现类:
2.1 XmlBeanDefinition
XmlBeanDefinitionReader就是从读取Xml里面的配置,然后生成BeanDefinition.
private static void xmlBeanDefinitionTest() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(applicationContext);
int i = reader.loadBeanDefinitions("spring.xml");
System.out.println(i);
}
2.2 AnnotatedBeanDefinitionReader
AnnotatedBeanDefinitionReader是解析一个类其他的注解,然后生成一个AnnotatedBeanDefinition.
private static void annotatedBeanDefinitionTest() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(applicationContext);
// 不管Person.class这个类上面有没有Component注解都会解析其他注解,比如@Scope和@Lazy等
reader.register(Person.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("person"));
}
2.3 ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner是指定一个包路径,然后进行扫描,获取beanDefinition,接着用refresh就可以把实例创建出来。
这里可以扫描@Service和@Component等注解,但是不能扫描@Bean注解
这个并不是BeanDefinitionReader,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition
2.4 BeanFactory
Spring中比较核心的是BeanFactory的实现类是DefaultListableBeanFactory
我们先从DefaultListableBeanFactory的继承结构说起
AliasRegistry:支持别名功能,一个名字可以对应多个别名,主要的方法如下:
- 注册别名
- 删除别名
- 判断这个名字是否别名
- 指定名字获取别名
他的一个简单地实现类是:SimpleAliasRegistry(现在不做过多的解读)
BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
SingletonBeanRegistry:可以直接注册、获取某个单例Bean
[图片上传失败...(image-528ee7-1614005134434)]
DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
有一种场景,如果你在beanFactory里面获取不到一个bean,他会自动从他父beanFactory里面获取这个bean
ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
FactoryBeanRegistrySupport:支持了FactoryBean的功能
ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个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(User.class); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册BeanDefinition beanFactory.registerBeanDefinition("user", beanDefinition); // 注册别名 beanFactory.registerAlias("user", "user1"); // 注册BeanPostProcessor beanFactory.addBeanPostProcessor(new LubanBeanPostProcessor()); // 获取Bean对象 System.out.println(beanFactory.getBean("user1")); // 根据类型获取beanNames System.out.println(beanFactory.getBeanNamesForType(User.class));
2.5 ApplicationContext
首先ApplicationContext是个接口,可以把它理解为一个特殊的BeanFactory
HierarchicalBeanFactory:拥有获取父BeanFactory的功能
System.out.println(applicationContext.getParentBeanFactory());
ListableBeanFactory:拥有获取beanNames的功能
System.out.println(applicationContext.getBeanDefinitionNames());
ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
Resource resource = applicationContext.getResource("spring.xml"); System.out.println(resource.contentLength());
EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
ConfigurableEnvironment environment = applicationContext.getEnvironment(); System.out.println(environment.getSystemProperties()); System.out.println(environment.getSystemEnvironment());
ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
applicationContext.publishEvent("xxx");
MessageSource:拥有国际化功能
System.out.println(applicationContext.getMessage("test", null, new Locale("")));
2.6 AnnotationConfigApplicationContext
- ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
- AbstractApplicationContext:实现了ConfigurableApplicationContext接口
- GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
- AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
- AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能
3 类型转换
3.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 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属性就能正常的完成属性赋值
3.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 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.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);