- BeanDefinition
Spring中定义bean的方式
@Bean
@Component
<bean/>
还可以通过BeanDefinition来定义一个bean
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//定义一个bean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(CouponAuditDO.class);
//设置其他属性
beanDefinition.setScope("prototype");
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); // 设置自动装配模型
//将BeanDefinition注册到BeanFactory中
beanFactory.registerBeanDefinition("couponAuditDo", beanDefinition);
// 获取Bean
System.out.println(beanFactory.getBean("couponAuditDo"));
通过,@Bean,@Component等方式所定义的Bean,最终都会被解析为BeanDefinition对象。
BeanDefinition可以理解为底层源码级别的一个概念,也可以理解为Spring提供的一种API使用的方式。
- BeanDefinitionReader
将bean解析转换成BeanDefinition,BeanDefinitionReader分为几类:
2.1 AnnotatedBeanDenfinitionReader
可以直接将某个类转换成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"));
2.2 XmlBeanDenfinitionReader
可以解析Spring.xml中bean标签
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(beanFactory.getBean("user"));
2.3 ClassPathBeanDenfinitionScanner
这个并不是BeanDefinitionReader,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition
- BeanFactory
Spring中比较核心的是BeanFactory的实现类是DefaultListableBeanFactory
- AliasRegistry:支持别名功能,一个名字可以对应多个别名
- BeanFactory:bean工厂,根据bean的类型,名字,别名获取对应的bean
- SingletonBeanRegistry:注册,获取某个单例bean
- SimpleAliasRegistry:实现AliasRegistry中定义的所有功能,支持别名功能
- BeanDefinitionRegistry:注册,保存,移除,获取某个BeanDefinition
- ListableBeanFactory:在beanFactory的基础上增加了可以获取所有BeanDefinition的beanNames,根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
- HierarchicalBeanFactory:在beanFactory的基础,增加获取父类在beanFactory的功能
- DefaultSingletonBeanRegistry:实现SingletonBeanRegistry中所有功能,同时支持别名功能
- FactoryBeanRegistrySupport:支持FactoryBean功能
- ConfigurableBeanFactory:增加设置父类BeanFactory,类加载器,设置Spring EL表达式解析器,设置类型转化服务,添加BeanPostProcessor,可以合并BeanDefinition,可以销毁某个bean等功能
- AbstractBeanFactory:实现了ConfigurableBeanFactory,并继承FactoryBeanRegistrySupport
- AutowireCapableBeanFactory:在BeanFactory基础上,支持在创建bean的过程中对bean进行自动装配
- AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
- ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
- DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大
- ApplicationContext
ApplicationContext是个接口,可以把它理解为一个特殊的BeanFactory
- ListableBeanFactory:可以获取beanNames
- HierarchicalBeanFactory:可以获取父BeanFactory
- ResourcePatternResolver:资源加载器,可以一次性获得多个资源(文件资源)
// 获取某个文件的内容
Resource resource = annotationConfigApplicationContext.getResource("file://D:\\spring-framework\\src\\main\\java\\com\\mandy\\entity\\User.java");
System.out.println(resource.contentLength());
还支持一次性获取多个
Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/mandy/service/*.class");
for (Resource resource : resources) {
System.out.println(resource.contentLength());
}
- EnvironmentCapable:获取运行时环境
// 获取JVM所允许的操作系统的环境
annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();
// 获取JVM本身的一些属性,包括-D所设置的
annotationConfigApplicationContext.getEnvironment().getSystemProperties();
// 还可以直接获取某个环境或properties文件中的属性
annotationConfigApplicationContext.getEnvironment().getProperty("test")
//还可以利用注解的方式
@PropertySource("classpath:application.properties")
- MessageSource:拥有国际化功能
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
applicationContext.getMessage("test", null, new Locale("en_CN"))
- ApplicationEventPublisher:拥有广播事件的功能
// 定义一个事件监听器
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}
//发布一个事件
applicationContext.publishEvent("kkk");
两个比较重要的实现类
4.1、ClassPathXmlApplicationContext
- ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
- AbstractApplicationContext:实现了ConfigurableApplicationContext接口
4.2、AnnotationConfigApplicationContext
相比ClassPathXmlApplicationContext支持的功能继续增加,而且拥有了BeanDefinitionRegistry功能
- GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory
beanFactory) - AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
- AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能
5.类型转换
举例使用场景,利用xml定义bean时,bean中属性的注入,即便是Integer类型,但是书写的是也是使用string类型,那么其中的转换则是由类型转换完成的
<bean id="dingTalkAlarm" class="com.xxx.common.business.alarm.DingTalkAlarm">
<constructor-arg name="title" value="业务通知"/>
<constructor-arg name="num" value="${noticenum}"/>
</bean>
- 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;
}
- 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;
}
- 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);
6.BeanPostProcessor
Bean的后置处理器,可以在创建每个Bean的过程中进行干涉,是属于BeanFactory中一个属性,在之后详情深入
- BeanFactoryPostProcessor
Bean工厂的后置处理器,是属于ApplicationContext中的一个属性,是ApplicationContext在实例化一个BeanFactory后,可以利用BeanFactoryPostProcessor继续处理BeanFactory。
可以通过BeanFactoryPostProcessor间接的设置BeanFactory,比如上文中的CustomEditorConfigurer就是一个BeanFactoryPostProcessor,我们可以通过它向BeanFactory中添加自定义的PropertyEditor。
- FactoryBean
关于FactoryBean在之前的文章中讲过《FactoryBean与BeanFactory不同》简单来说,允许自定义一个对象通过FactoryBean间接放到Spring容器中成为bean,补充之前文章缺少知识点
FactoryBean和@Bean有何不同?
@Bean也可以自定义一个对象,让这个对象成为一个Bean。
区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。
整体来说就是相比FactoryBean,@Bean的功能过于单一了。