Spring IOC
IOC
(Inversion of Control) :控制反转,是一种思想,不是技术。将原本在程序中手动创建对象的控制权,交由程序来管理。
- Spring Core 最核心的部分。
- 需要先了解依赖注入(Dependency Inversion)
什么是 DI
上层建筑依赖下层建筑. 从上到下创建.(依赖方向)
用 DI
来实现 IOC
.
含义 : 把底层类作为参数传递给上层类, 实现上层对下层的”控制”. 从下到上开始创建(注入)。
IOC
, DI
, DL
(Dependency Lookup, 依赖查找)的关系.
依赖注入的方式
- Setter, Set方法
- Interface, 接口
- Constructor, 构造器
- Annotation, 注解
依赖倒置原则, IOC, DI, IOC容器的关系
依赖倒置原则 : 高层模块不应该依赖底层模块, 两者应该依赖抽象.
有了这个思想才有了 IOC
, 而 IOC
的实现 依靠 依赖注入 的支撑.
基于 IOC
提出了 IOC容器
概念, 容器管理 bean
的生命周期, 控制着 bean
的依赖注入.
IOC
容器的优势:
- 避免了在各处使用
new
来创建类, 并且可以做到统一维护. 这个容器会自动对代码进行初始, 你需要维护一个Configuration
就可以了. - 创建实例的时候不需要了解其中的细节.
上面的例子, 是从下往上 new 的.
而IOC容器
如下, 蓝色部分是隐藏的细节.
Spring IOC 原理
利用 Java 的反射功能实例化 bean
.
Spring IOC 支持的功能
- 依赖注入
- 依赖检查
- 自动装配
- 支持集合
- 指定初始化方法和销毁方法
- 支持回调方法(要实现接口, 略带侵略性)
Spring IOC 容器的核心接口
- BeanFactory
- ApplicationContext
BeanDefinition
- 主要用来描述Bean的定义(把注解的类或者是xml配置的类解析)
BeanDefinitionRegistry
是一个接口.
- 提供向 IOC 容器注册
BeanDefinition
对象的方法
默认注册到DefaultListableBeanFactory
.
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
BeanFactory
Spring 框架最核心的接口
- 提供
IOC
的配置机制 - 包含
Bean
的各种定义, 便以实例化Bean
- 建立
Bean
之间的依赖关系 Bean
生命周期的控制
BeanFactory
是顶级容器接口, DefaultListableBeanFactory
和BeanDefinitionRegistry
都是从它扩展来的.
ListableBeanFactory
: 定义了访问容器中Bean
基本信息的若干方法, 如查看Bean
的个数, 获取某一类型Bean
的配置名, 查看容器中是否包括某一Bean
等.HierarchicalBeanFactory
: 父子级联IOC
容器. 子容器可以通过接口方法访问父容器. 建立起父子层级关联的容器体系, 子容器可以访问父容器的Bean
, 但是父容器不能访问子容器的Bean
. 比如在 SpringMVC 中, 展现层的 Bean 位于一个子容器中, 而业务层和持久层的 Bean 位于父容器中, 这样展现层Bean
就可以引用业务层和持久层了, 而反过来就不行.ConfigurableBeanFactory
: 增强了IOC
容器的可定制性, 定义了设置类装载器, 属性编辑器以及属性初始化后置处理器.AutowrieCapableBeanFactory
: 定义了将容器中的Bean
, 按某种规则, 比如说按名字匹配, 按类型匹配等, 按照这些规则对Bean
进行自动装配.SingletonBeanRegistry
: 允许在运行期间, 向容器注册Singleton
实例Bean
的方法.
Spring IOC
中, Bean
默认都是 单例形式 存在的.
ApplicationContext
是 BeanFactory
的子接口之一.
- BeanFactory 是 Spring 框架的基础设施, 面向Spring.
- ApplicationContext面向使用Spring框架的开发者.
ApplicationContext 的功能(继承多个接口)
BeanFactory
: 能够管理, 装配Bean
ResourcePatternResolver
: 能够加载资源文件MessageSource
: 能够实现国际化等功能ApplicationEventPublisher
: 能够注册监听器, 实现监听机制
是应用上下文, 代表着整个容器的所有功能.
AnnotationConfigServletWebServerApplicationContext
是SpringBoot
的默认容器类.
// 返回的就是 ConfigurableApplicationContext
// SpringAppliction.run(xxx.class, args);
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 主要逻辑
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 创建上下文对象
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
getBean()
方法解析
在AbstractBeanFactory
类中, 最终其实调用的是doGetBean
方法。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 转换 beanName
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 获取是否有手动注册的单例对象
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果有, 从实例工厂或缓存中获取实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 尝试在父类工厂查找是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 获取类的定义 将父类和子类的进行合并
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
// 如果存在依赖, 先 递归 实现依赖bean, 解决循环依赖问题.
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 作用域是否是单例的, 判断之前是否已经创建过了. 有就直接返回, 没有就创建一个
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果是其它作用域, web容器还有其它作用域, 像 session, request
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// 检查创建的类型是否符合需要实例的类型
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
- 转换
beanName
- 尝试从缓存中加载实例
- 实例化Bean
- 检查
parentBeanFactory
- 初始化依赖的
Bean
- 创建
Bean
, 并且再检查一次Bean
的类型