1. BeanDefinition
BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如:
class,表示Bean类型
scope,表示Bean作用域,单例或原型等
lazyInit:表示Bean是否是懒加载
initMethodName:表示Bean初始化时要执行的方法
destroyMethodName:表示Bean销毁时要执行的方法
还有很多...
GenericBeanDefinition 是spring源码中BeanDefinition 常用的一个实现类;
RootBeanDefinition 后续补充。。。
2. BeanDefinitionReader
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解
注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析为BeanDefinition,放入到Spring 容器中
annotatedBeanDefinitionReader.register(User.class);
可以解析标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml"); //Bean 配置文件
它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition,放入spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.test"); // 包路径
3. BeanFactory
3.1 BeanFactory 与 ApplicationContext的区别
ApplicationContext是,在Spring源码中,是如下代码定义的;
- 我们发现 ApplicationContext 继承了 ListableBeanFactory和HierarchicalBeanFactory,而ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory, 可以认为ApplicationContext也是BeanFactory的一种,拥有BeanFactory支持的所有功能;
- ApplicationContext比BeanFactory更加强大,ApplicationContext还继承了其他接口,也就表示ApplicationContext还拥有其他功能,比如MessageSource表示国际化,ApplicationEventPublisher表示事件发布,EnvironmentCapable表示获取环境变量,等等。
// ApplicationContext是,在Spring源码中,是这么定义的
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
...
}
3.2 DefaultListableBeanFactory
BeanFactory接口存在一个非常重要的核心的实现类。
// DefaultListableBeanFactory的用法
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 定义Bean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
// 用DefaultListableBeanFactory注册Bean
beanFactory.registerBeanDefinition("user", beanDefinition);
System.out.println(beanFactory.getBean("user"));
它实现了很多接口,表示,它拥有很多功能 (可以先简单了解一些):
- 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的功能很强大
3.3 ApplicationContext
上面有分析到,ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory更加强大,比如:
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源。(下边 3.3.2 的应用)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)(下边 3.3.2 的应用)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)(下边 3.3.4 的应用)
- MessageSource:拥有国际化功能 (下边 3.3.3 的应用)
3.3.1 ApplicationContext两个比较重要的实现类:
都继承了AbstractApplicationContext,但ClassPathXmlApplicationContext相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition。
AnnotationConfigApplicationContext
ClassPathXmlApplicationContext
3.3.2 ApplicationContext 资源加载
- 利用ApplicationContext获取某个文件的内容:
代码示例:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Resource resource = context.getResource("file://D:\\learning\\spring-framework-5.3.10\\src\\main\\java\\com\\zhouyu\\service\\tesrService.java");
System.out.println(resource.contentLength());
- 利用ApplicationContext获取获取运行时环境
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取操作系统的环境变量
Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
// Java 运行指定的参数变量
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
// 获取配置文件中的变量
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("zhouyu"));
3.3.3ApplicationContext 中的 MessageSource 国际化
略
3.3.4 事件发布
// 1. 先定义监听器--------------------------------------------------------------------------------------------------------------------------------
public class AppConfig {
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}
// 2. 定义事件发布--------------------------------------------------------------------------
@Component
public class PublishEventService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
// 事件发布
public void test(){
applicationContext.publishEvent("test");
System.out.println("发布成功");
}
}
// 3 调用发布事件----------------------------------------------------------------------------------------------------------
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//调用发布事件
PublishEventService publishEvent = (PublishEventService) applicationContext.getBean("publishEventService");
publishEvent.test();
}
4 类型转化
在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 在源码的会遇到很多,提前熟悉类型转化能帮助更快速的解读源码。
代码应用
// 1 定义转化器
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);
}
}
// 2 java 调用转化器 的方式
public static void main(String[] args){
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);
}
// 3 在spring的中调用的方式
// 向Spring中注册PropertyEditor:
public class AppConfig {
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
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;
}
}
// 可以在spring中如下调用
@Component
public class UserService {
@Value("name") // 此时设置user时会发现值是String,就会启用配置的类型转化类的设置
private User user;
public void test() {
System.out.println(user);
}
}
代码应用
// 1. 定义自己的转类,实现ConditionalGenericConverter 接口
public class StringToUserConverter implements ConditionalGenericConverter {
/**
* 定义转化匹配条件,如下当源类型是String,目标转化类型是User的时候才进行转化
*/
@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;
}
}
// 2 注册 CustomEditorConfigurer
public class AppConfig {
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
// 把自己定义的转化类设置进去
conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
return conversionServiceFactoryBean;
}
}
// 3 业务逻辑中调用转化方法
{
// 1. 实例化一个 类型转化服务器 conversionService
DefaultConversionService conversionService = new DefaultConversionService();
// 2. 将自己定义的转化类 StringToUserConverter 放入到conversionService
conversionService.addConverter(new StringToUserConverter());
// 3. 调用convert方法进行转化
User value = conversionService.convert("1", User.class);
System.out.println(value);
}
{
// 1. 实例化一个 typeConverter
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
// 2. 设置自己定义的一个JDK PropertyEditor 转化器,StringToUserPropertyEditor
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
// 2. 也可以设置自己定义的spring 类型转化器-conversionService, conversionService定义步骤参考上述
//typeConverter.setConversionService(conversionService);
// 3. 调用转化方法进去转换
User value = typeConverter.convertIfNecessary("1", User.class);
System.out.println(value.getName());
}
5 OrderComparator 比较器
OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行比较,从而可以进行排序。
实现Ordered接口 来执行比较
/* 测试类A*/
public class testA implements Ordered {
@Override
public int getOrder() {
return 3;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
/* 测试类B*/
public class testB implements Ordered {
@Override
public int getOrder() {
return 2;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
/* 运用 OrderComparator 比较器排序*/
public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
OrderComparator comparator = new OrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // B,A
}
}
根据@Order注解来执行比较
Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。
/* 测试类A*/
public class testA implements Ordered {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
/* 测试类B*/
public class testB implements Ordered {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
/* 运用 AnnotationAwareOrderComparator 比较器排序*/
public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
list.sort(comparator); // 按order值升序排序
System.out.println(list); // B,A
}
}
6 BeanPostProcessor Bean后置处理器
BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcesson;
一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,
当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean);
(即 可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程)
示例代码:
@Component
public class NingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化前");
//...
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化后");
// ...
}
return bean;
}
}
7 BeanFactoryPostProcessor Bean工厂后置处理器
BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程
示例代码:
@Component
public class NingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
// ...
}
}
8 FactoryBean
可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的;
如果说BeanFactory是Bean 的自动化操作的话,FactoryBean 可以说是Bean的一定程度的手动操作模板,Spring在容器启动创建实例化Bean的时候,允许开发者有一定的权限来干涉自己所创建的Bean的条件;
通过FactoryBean获取Bean,代码示例:
@Component
public class NingFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
// 获取Bean
public class ningApplication {
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("ningFactoryBean")); // 获取的是 com.ning.service.UserService@7a92922
System.out.println(applicationContext.getBean("&ningFactoryBean")); // 获取的是 com.ning.service.NingFactoryBean@2d6d8735
}
}
@Bean生成一个对象作为Bean和FactoryBean的区别是什么呢?
很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。而FactoryBean 的Bean只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。
通过如下实验示例来体验一下:
// 1. 实现一个BeanPostProcessor ,看初始化前和后的两个方法调用情况
@Component
public class NingBeanPostProcesser implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("ningFactoryBean".equals(beanName)){
System.out.println("初始化前"+bean);
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("ningFactoryBean".equals(beanName)){
System.out.println("初始化后"+bean );
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
// 2. 调用打印实验结果
public class ningApplication {
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("ningFactoryBean"));
/* 实验结果如下,UserService Bean只会经历初始化后
初始化前com.ning.service.NingFactoryBean@12bc6874
初始化后com.ning.service.NingFactoryBean@12bc6874
初始化后com.ning.service.UserService@77f03bb1*/
}
}
9 ExcludeFilter和IncludeFilter 过滤器
这两个Filter是Spring扫描过程中用来过滤的。
ExcludeFilter表示排除过滤器;
FilterType分为:
- ANNOTATION:表示是否包含某个注解
- ASSIGNABLE_TYPE:表示是否是某个类
- ASPECTJ:表示否是符合某个Aspectj表达式
- REGEX:表示是否符合某个正则表达式
- CUSTOM:自定义
IncludeFilter表示包含过滤器。
在spring进去扫码包的时候默认添加了一个包含过滤器,添加了@component的类默认会被扫描注册到Spring 容器中,这也是我们在编码的时候被@component注解注释的类会被注册到sipng容器
// Spring 中的源码
this.includeFilters.add(new AnnotationTypeFilter(Component.class)
过滤器的简单应用代码示例:
// 不去注册UserService.
@ComponentScan(value = "com.ning",
excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)}.) // 排除UserService类
public class AppConfig {
}
// 不加注解也可以注册UserService.
@ComponentScan(value = "com.zhouyu",
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
public class AppConfig {
}
10 类的元数据,MetadataReader、ClassMetadata、AnnotationMetadata
Spring中对类的元数据(类名、类中的方法、类上的注解…等这些元数据信息)做了抽象,并提供了一些工具类,用于解析类的信息。
需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。
为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不好,所以使用了ASM技术(并不把类加载到内存中,读取分析文件直接拿到这个文件资源去解析读取信息)。
// 元数据类的简单应用代码
public class Test {
public static void main(String[] args) throws IOException {
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
// 构造一个MetadataReader
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.zhouyu.service.UserService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 获取一个AnnotationMetadata,并获取类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
System.out.println(annotationType);
}
}
}