目录
目标
介绍springcore中的IOC,阐述通过源码了解的原理。
IOC
IOC定义
IOC或者DI是仅可以通过[构造函数参数][工厂方法参数][由构造函数或工厂方法生成的实例的setter方法]3种方式[为很多对象构建依赖关系]的过程。
因为这个过程是[对象自己控制依赖对象的实例化]的彻底反转,因此起名为控制反转IOC
IOC容器
IOC容器是org.springframework.context.ApplicationContext的一个具体实例,根据配置信息进行实例化/配置/组装bean,输出一个全配置性且可运行的系统。
来自spring官网的图示
相关的包
- org.springframework.beans/context;
相关接口
- BeanFactory,提供管理各种对象的配置能力;
- ApplicationContext,是BeanFactory的子接口,添加了对新特性的集成,如AOP。
- FactoryBean接口,在BeanFactory中使用,负责生成特定类型bean。
Bean
BeanDefination
在IOC容器中,所有bean都以BeanDefination形式表现的。
创建一个beanDefination,就相当于获取到一个[通过beandifination创建class的很多实例]的秘诀;不仅可以控制实例的依赖和配置,而且可以控制实例的scope。
包含关于bean的元数据
- 全路径class名称
- 在IOC容器内的行为配置信息,如scope lifecycle等
- 对其他bean的引用,成为合作者或依赖
- 创建实例时的配置信息,如创建线程池时对线程数量的配置
实例化
构造函数的方式
静态工厂方法,bean的class中有静态工厂方法
实例化工厂方法
bean scope bean的使用范围
singleton 单例
(Default) Scopes a single bean definition to a single object instance per Spring IoC container.
默认配置,该scope的bean定义,在每个IOC容器中生成一个单例对象。
来自spring官网的图示
prototype 原型
Scopes a single bean definition to any number of object instances.
当bean定义的实例被需要时,就会新建一个对象实例。
来自spring官网图示
web相关
request
Scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
每一个HTTP请求都具有一个独立的对象实例。
session
Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
每一个HTTP会话都具有一个独立的对象实例
globalSession
Scopes a single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a Portlet context. Only valid in the context of a web-aware Spring ApplicationContext.
application
Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
每个ServletContext具有一个独立的对象实例
websocket
Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
web范围bean的注入需要DispatcherServlet RequestContextListener RequestContextFilter:使用name方式,将HTTP请求需要的bean绑定到HTTP请求的当前线程中,包括request session scope的bean。
自定义bean的本质
自定义bean的本质就是自定义生命周期扩展点。
具体bean的生命周期回调lifecycle callback
- 初始化回调:当bean配置的属性依赖,已经由IOC容器通过setter设置完成后,会调用bean回调方法。
- 最佳实践为:使用方法上添加@PostConstruct或者bean配置init-method
不建议使用
org.springframework.beans.factory.InitializingBean
void afterPropertiesSet() throws Exception;
- 解构回调:当IOC容器正在销毁时,调用bean的回调方法。
- 最佳实践为:方法上添加@PreDestroy或bean配置destroy-method
不建议使用接口
org.springframework.beans.factory.DisposableBean
void destroy() throws Exception;
所有bean实例初始化前后的处理
BeanPostProcessor
- postProcessBeforeInitialization 在当前新建bean的所有初始化回调之前
- postProcessAfterInitialization 在当前新建bean的所有初始化回调之后
举例
CommonAnnotationBeanPostProcessor | 初始化回调前,@Resource根据beanName依赖注入,初始化@PostConstruct方法执行 |
AutowiredAnnotationBeanPostProcessor | 初始化回调前,对使用@autowired @value注解的field、setter进行依赖注入 |
ConfigurationPropertiesBindingPostProcessor #postProcessBeforeInitialization | 初始化回调前,为@ConfigurationProperties相关的filed赋值 |
AbstractAdvisingBeanPostProcessor #postProcessAfterInitialization | 在所有初始化回调后,生成代理 |
BeanFactory初始化后进行扩展
BeanFactoryPostProcessor
BeanFactory初始化后,进行Component扫描等工作,加载bean,但不进行实例化。
举例
集成到spring的中间件会在此做些扩展,如mybatis按照路径规则扫描并向beanfactory注册bean。
Aware
applicationContextAware IOC容器创建实例后调用该接口实现类的回调setApplicationContext
beanNameAware IOC容器创建实例并设置属性依赖后,调用回调方法setBeanName,然后调用初始化回调方法。
如何在@bean方法中获取到某种类型的所有bean?
例如我想获取到所有RedisTemplate bean。
使用org.springframework.beans.factory.ObjectProvider
@Bean
public Object test(ObjectProvider<RedisTemplate[]> tps) {
RedisTemplate[] ifAvailable = tps.getIfAvailable();
System.out.println();
return null;
}
Spring中有用的技巧
-
扫描classpath并获取符合要求的类
使用到的类:ClassPathScanningCandidateComponentProvider
public static void scannerPackage(String[] packages, TypeFilter[] typeFilters, Consumer<Class<?>> consumer) {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
for (TypeFilter filter : typeFilters) {
scanner.addIncludeFilter(filter);
}
for (String pack : packages) {
for (BeanDefinition bd : scanner.findCandidateComponents(pack)) {
consumer.accept(Class.forName(bd.getBeanClassName()));
}
}
}
AOP
详见后续章节
事务
详见后续章节