Spring源码分析(一)核心概念记录
1:BeanDefinition
spring主要是为了管理项目中的类和实例的,我们定义的类几种方式xml,注解,@Bean等在被spring读取到之后Spring内部维护我们定义的类的数据结构就是BeanDefinition,它是一个接口,里面定义类的className,是否是单例,是否是懒加载等等属性。
BeanDefinitionReader:
AnnotatedBeanDefinitionReader
可以直接把某个类转换为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"));
XmlBeanDefinitionReader
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml"); System.out.println(beanFactory.getBean("user"));
ClassPathBeanDefinitionScanner
这个并不是BeanDefinitionReader,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition
2:容器的继承体系
在Spring中我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,它作为Spring容器的顶级接口,这系列容器只实现了容器的基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上增加了许多面向框架的特性,同时对应用环境做了适配。
AliasRegistry:
管理别名的接口,实现这个接口可以对容器中的某个Bean进行起别名。还可以判断某个名字是否是别名,列出所有的别名。
SimpleAliasRegistry:
上面接口的简单实现类。
BeanDefinitionRegistry:
是一个注册器接口,实现这个接口可以向容器里面单独注册Bean,是以BeanDefinition为对象的实例注册进去,GenericApplicationContext,DefaultListableBeanFactory都实现了这个接口。
BeanFactory:
spring顶层容器接口,它只定义了容器的基本功能,从容器中获取bean,bean是否是单例等基本功能。
SingletonBeanRegistry:
向单例对象池注册单例对象,获取一个单例bean,判断一个bean是否为单例等单例相关的操作的接口。
DefaultSingletonBeanRegistry:
上面接口的一个实现类,类里定义了单例对象池:singletonObjects,以及早期单例对象(和循环依赖相关)等和单例对象相关的操作。
HierarchicalBeanFactory:
接口,提供设置获取父子容器的功能,但是当前这个接口里只有只有BeanFactory getParentBeanFactory(); 方法,setParentBeanFactory在子接口 ConfigurableBeanFactory中有定义。
ListableBeanFactory:
接口,直接继承BeanFactory,除了基本的容器功能外,提供了一些列出容器中的相关信息的操作比如,是否包含某个BeanDefinition的定义,得到所有的BeanDefinition的name,根据类型获取BeanName等等操作。
FactoryBeanRegistrySupport:
类,继承了DefaultSingletonBeanRegistry类,是一个factorybean,维护了一个被FactoryBeans创建的单例对象池。
ConfigurableBeanFactory:
接口,继承了HierarchicalBeanFactory, SingletonBeanRegistry,额外提供了一些可以配置BeanFactory的功能,比如 setParentBeanFactory:设置父容器。setBeanClassLoader:设置bean加载的classloader。setConversionService:设置转换器。addBeanPostProcessor:添加后置处理器。等等set方法,如果使用的BeanFactory没有实现这个接口这些set方法设置的内容就是spring默认的了。实现这个接口就是可以自定义。
AbstractBeanFactory:
抽象类,继承了FactoryBeanRegistrySupport,实现了ConfigurableBeanFactory,相关的功能已经实现好了,但是不能自动装配和获取beanNames。
AutowireCapableBeanFactory:
接口,是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配。
AbstractAutowireCapableBeanFactory:
继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能而且可以配置BeanFatcoty,功能也是比较完善的,但是它还没有ListableBeanFactory的功能。
ConfigurableListableBeanFactory:
接口,继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory,所以有了可配置BeanFactory,自动注入,和获取bean相关信息的功能。
DefaultListableBeanFactory:
终极的一个功能很完善的spring容器,继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大。还具有注册的功能。
3:ApplicationContext
ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上增加了许多面向框架的特性,同时对应用环境做了适配.
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
- MessageSource:拥有国际化功能
又两个比较重要的实现类:
- AnnotationConfigApplicationContext
- ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
- ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
- AbstractApplicationContext:实现了ConfigurableApplicationContext接口
- GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
- AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
- AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能
ClassPathXmlApplicationContext
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition
国际化
先定义一个MessageSource:
@Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; }
有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。
同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:
annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))
资源加载
ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:
Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java");
System.out.println(resource.contentLength());
你可以想想,如果你不使用ApplicationContext,而是自己来实现这个功能,就比较费时间了。
Resource resource = annotationConfigApplicationContext.getResource("classpath:com/luban/entity/User.class");
System.out.println(resource.contentLength());
还可以一次性获取多个资源:
Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/luban/service/*.class"); for (Resource resource : resources) { System.out.println(resource.contentLength()); }
这个功能用到了策略模式。
获取运行时环境
// 获取JVM所允许的操作系统的环境 annotationConfigApplicationContext.getEnvironment().getSystemEnvironment(); // 获取JVM本身的一些属性,包括-D所设置的 annotationConfigApplicationContext.getEnvironment().getSystemProperties(); // 还可以直接获取某个环境或properties文件中的属性 annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")
还可以利用下面的注解把某个properties文件中的参数添加到运行时环境中
@PropertySource("classpath:application.properties")
事件发布
@Bean public ApplicationListener applicationListener() { return new ApplicationListener() { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("接收到了一个事件"); } }; }
然后发布一个事件:
annotationConfigApplicationContext.publishEvent("kkk");
类型转换器
在项目中使用默认的类型转换器不能满足要求的时候,可能要自定义类型转换器。比如String转成User对象。
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<?>, 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属性就能正常的完成属性赋值
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<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; }
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);
BeanPostProcessor
Bean的后置处理器,可以在创建每个Bean的过程中进行干涉,是属于BeanFactory中一个属性,讲Bean的生命周期中详细讲。
BeanFactoryPostProcessor
Bean工厂的后置处理器,是属于ApplicationContext中的一个属性,是ApplicationContext在实例化一个BeanFactory后,可以利用BeanFactoryPostProcessor继续处理BeanFactory。
可以通过BeanFactoryPostProcessor间接的设置BeanFactory,比如上文中的CustomEditorConfigurer就是一个BeanFactoryPostProcessor,我们可以通过它向BeanFactory中添加自定义的PropertyEditor。
FactoryBean
允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean。可以对一个Bean的创建进行高级设置。而BeanFactory是创建很多bean的工厂。
那么它和@Bean的区别是什么?因为@Bean也可以自定义一个对象,让这个对象成为一个Bean。
区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以让它再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。
接口有一个默认的方法,isSingleton返回true.另外两个方法需要自己实现。
这个factorybean可以实现其它接口来获取更多的spring相关的属性,而@Bean方法则不行。
而且我们通过application.getBean("myFactoryBean"); 得到的是getObject返回的对象,而且根据isSingleton的返回是否为单例。如果要得到MyFactoryBean本身,需要用getBean("&myFactoryBean");
SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()); //typeConverter.setConversionService(conversionService); User value = typeConverter.convertIfNecessary("1", User.class); System.out.println(value);