spring中的几个核心概念,在看源码前先了解这些概念,后面再去看源码会更容易理解源码。
bean的定义,它存储着一个bean对象需要的各种信息,如class信息、beanName、作用范围scope等信息,那么为什么要有这个定义呢?spring是扫描class字节码文件加载类的,在启动时扫描一次,之后我们要通过getBean获取一个bean,要判断这个bean是否懒加载,是否单例等等,那么这时候就不能再去解析了,因为在启动时就扫描解析过一次了,所以在第一次扫描解析会把bean的各种信息保存用来创建bean,这就是beanDefinition的作用。
定义bean的方式:
如下一个通过beanDefinition去注册到容器,然后创建bean的一个例子
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// UserService userService = applicationContext.getBean("userService", UserService.class);
//
// userService.test();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(MenuService.class);
beanDefinition.setScope("singleton");
applicationContext.registerBeanDefinition("MenuService", beanDefinition);
MenuService bean = applicationContext.getBean(MenuService.class);
System.out.println(bean);
beanDefinition的读取器,用于注册beanDefinition, 提供了注册、获取资源加载器、获取类加载器、beanname生成、加载beanDefinition等接口。
分xml方式的和注解方式的:
XmlBeanDefinitionReader
:扫描标签AnnotatedBeanDefinitionReader
:扫描由注解定义的类,能够解析的注解:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@DescriptionClassPathBeanDefinitionScanner
:和上面两个一样,多了一个路径扫描,并将扫描到的含有注解的类注册 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);
关于为什么XmlBeanDefinitionReader
、AnnotatedBeanDefinitionReader
这个两个不是同一个beanDefinitionReader接口,我是这样理解的,原先的BeanDefinitionReader
接口所实现的功能是针对xml的,从它的接口定义可以看出,加载beanDefinition是通过路径去读的,而AnnotatedBeanDefinitionReader
功能和xml的功能一样,但其实现却有根本的区别,一个是读取xml路径,加载beanDefinition,一个是通过class加载。
beanFactory有存放bean,生成bean的功能,但它只是一个接口,spring中最核心的是DefaultListableBeanFactory
,它是beanFactory最底层的类,获取beanDefinition、注册beanDefinition、别名功能、bean注册、获取bean、自动装配功能等等。
因为启动spring就是创建beanFactory,然后扫描bean的定义,拿到beanFactory,创建bean,再通过beanFactory拿到bean。
图中的说明并不完善,只是觉得在上面标的话会更加清晰,就不用一个个去找了。
首先ApplicationContext
不止继承了beanFactory,还有registry、resourceLoader等,可以完成资源加载、解析、注册bean、获取bean等功能。
这个功能比起AnnotationConfigApplicationContext
没有注册beanDefinition功能。
可配置国际通用的配置,配置格式:文件基础名称_语言.properties
// 这种文件基础名称
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message");
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, new Locale("zh_ch")));;
获取中文的信息出现乱码是因为编码的不同
"
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"));
可以做到如下的操作
// 获取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;
}
}
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}
applicationContext.publishEvent("ss");
这里出现两次打印,是因为在spring启动完后会有一次,然后我手动调用一次,一共两次
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());
对比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());
这个转换器整合了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());
bean的后置处理器,可以在创建每个Bean的过程中进行干涉,如在bean的实例化前或后,修改bean,或者做一些处理,如aop
bean工厂的后置处理器,可以对beanFactory继续设置,比如修改beanFactory的属性,增加xml方式注入的忽略接口等。
它和beanFactory不一样,首先factoryBean可以注册成为一个bean,而它的子类更是添加了获取bean工厂的接口,如AbstractFactoryBean
,继承子类你就有了bean工厂的功能。
理解的话,有点像工厂模式,用于生产某个bean的,它的getObject方法只调用一次。