什么是IOC,什么又是DI,他们有什么区别?

一、IOC介绍
IOC是控制反转。
创建对象实例的控制权从代码控制剥离到IOC容器控制(之前的写法,由程序代码直接操控使用new关键字),实际就是你在xml文件控制,控制权的转移是所谓反转,侧重于原理。

二、DI介绍
DI是依赖注入
创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

三、区别
1.它们是spring核心思想的不同方面的描述。
2.依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。

依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;
而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

有哪些不同类型的IOC(依赖注入)方式?

构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。

哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入?

你两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。

spring中的核心类有那些,各有什么作用?

答:BeanFactory:产生一个新的实例,可以实现单例模式
BeanWrapper:提供统一的get及set方法
ApplicationContext:提供框架的实现,包括BeanFactory的所有功能

Spring中用到的设计模式,并举具体示例

Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:

代理模式—在AOP和remoting中被用的比较多。
单例模式—在spring配置文件中定义的bean默认为单例模式。
工厂模式—BeanFactory用来创建对象的实例。

什么是bean装配?

装配,或bean 装配是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。

什么是bean的自动装配?

Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能通过Bean工厂自动处理bean之间的协作。</property></constructor-arg>

解释不同方式的自动装配

有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。

no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。

自动装配有哪些局限性 ?

自动装配的局限性是:

重写: 你仍需用 <constructor-arg>和 <property> 配置来定义依赖,意味着总要重写自动装配。
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。</property></constructor-arg>

构造方法注入和设值注入有什么区别?

请注意以下明显的区别:
在设值注入方法支持大部分的依赖注入,如果我们仅需要注入int、string和long型的变量,我们不要用设值的方法注入。
对于基本类型,如果我们没有注入的话,可以为基本类型设置默认值。
在构造方法注入不支持大部分的依赖注入,因为在调用构造方法中必须传入正确的构造参数,否则的话为报错。

设值注入不会重写构造方法的值。
在使用设值注入时有可能还不能保证某种依赖是否已经被注入,也就是说这时对象的依赖关系有可能是不完整的。而在另一种情况下,构造器注入则不允许生成依赖关系不完整的对象。

Spring Bean的作用域之间有什么区别?

Spring容器中的bean可以分为5个范围。所有范围的名称都是自说明的,但是为了避免混淆,还是让我们来解释一下:

singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。

全局作用域与Servlet中的session作用域效果相同。

请介绍一下Spring框架中Bean的生命周期

一、Bean的定义
Spring通常通过配置文件定义Bean。如:
这个配置文件就定义了一个标识为 HelloWorld 的Bean。在一个配置文档中可以定义多个Bean。

二、Bean的初始化
有两种方式初始化Bean。
1、在配置文档中通过指定init-method 属性来完成
2、实现 org.springframwork.beans.factory.InitializingBean接口

那么,当这个Bean的所有属性被Spring的BeanFactory设置完后,会自动调用afterPropertiesSet()方法对Bean进行初始化,于是,配置文件就不用指定 init-method属性了。

三、Bean的调用
有三种方式可以得到Bean并进行调用:
1、使用BeanWrapper
2、使用BeanFactory
3、使用ApplicationConttext

四、Bean的销毁
1、使用配置文件中的 destory-method 属性
2、实现 org.springframwork.bean.factory.DisposebleBean接口

Spring中IOC的作用与原理?对象创建的过程。

Spring 中的 IoC 的实现原理,就是工厂模式加反射机制。
可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性

ApplicationContext通常的实现是什么?

ApplicationContext是Spring的上下文,定义了IOC容器初始化的过程,从类结构上可以看到,它也是一个BeanFactory,还是一个ResourceLoader资源加载器,同时它还是ApplicationContext,扩展了IOC容器初始化的过程,在其注册Bean时还是使用上文提到的DefaultListableBeanFactory这个BeanFactory,而ApplicationContext存在的意义就是完善(增添)了IOC容器的功能,使获取Bean更加灵活,功能更多样。

可以看到最底层有四种不同的ApplicationContext,它们各自有各自不同的方法加载Bean,从类名上也都可以看出来,AnnotationConfigWebApplicationContext与XmlWebApplicationContext主要用于Web,一种是根据注解的方式加载Bean信息,一种是根据xml文件加载Bean信息。而FileSystemXmlApplicationContext与ClassPathXmlApplicationContext一种是从文件系统资源来加载Bean定义,一种是从路径获取加载Bean定义,其实这些ApplicationContext大同小异,他们都间接继承了AbstractApplicationContext与其子类,这两个类实现了大部分初始化IOC容器的方法,而那四种ApplicationContext的区别只在读取Bean资源的方式上,与应用场景不同上,本质的IOC容器初始化原理都是相同的。

FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。

ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。

WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

Bean 工厂和 Application contexts 有什么区别?

beanFactory是最底层的容器,提供了实例化bean以及获取bean的方法。
ApplicationContext 继承beanFactory接口,提供了更多的功能,比如国际化、访问资源、aop等。

两者子装载bean的方式上有所差异:beanFactory在初始化的时候不会创建bean,有方法来获取的时候才会去创建。
ApplicationContext一开始就会创建好所有的bean。

factoryBean与beanFactory的区别

BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

BeanFactory

Spring 对Bean的操作是典型的工厂模式,上面定义了许多不同的BeanFactory,都是具有它各种各样不同的功能的,这些BeanFactory们为操作Bean带来了极大的便利。最底层的DefaultListableBeanFactory实现了以上所有接口,我们使用的默认的BeanFactory即为此类.

包含方法:
getBean:获取Bean实例的方法。
containsBean:验证IOC容器是否有某个bean的方法。
getType:获取bean的class类型的方法。
getAliases:获取bean的别名的方法。

FactoryBean

它是一个特殊的Bean,从名字就可以看出来,它是由Bean结尾的,意味着是一个Bean,但此Bean是工厂类型的Bean,什么意思呢?普通Bean只是IOC容器管理的真正代码中使用的对象,但工厂Bean不是我们要使用的对象,它负责生产真正的Bean,它是一个工厂,但它也是由工厂(BeanFactory)生产出来的,也就是说,FactroyBean是用来生产Bean而生的。

FactoryBean是Spring定义的一个特殊的Bean,包含的方法:
getObeject:定义了一个获取Bean对象的方法。
getObjectType:定义了一个获取Bean的Class对象的方法。
isSingleton:判断此Factory生成的Bean是否为单例Bean,默认为true。

Factory是一个特殊的Bean ,主要用途是用来生产Bean的,请注意IOC容器中singletonObjects这个Map将会存放所有初始化好的单例Bean(包括那些单例的FactoryBean),而factoryBeanObjectCache存放的则是那些FactoryBean生产出来的Bean,也就是说,IOC容器不仅会存放FactoryBean在容器中,还会存放FactoryBean生产的Bean在容器中,双重缓存加快获取Bean的效率。这里读者要理清两者的关系。

bean的创建过程

IOC容器对资源的定位(根据路径定位资源)、加载(根据一定规则加载资源成为一个可解析的对象)、注册(将封装好了的Bean信息对象存放进BeanFactory中的Map里,并且使用List存放BeanName)。然而,这个过程只是一个开始,此时的Bean还未初始化,BeanFactory中只是存放了Bean的描述定义对象而已,真正初始化是在getBean()方法被调用。

BeanFactory会遍历所有的Bean,如果是单例且lazy-init=false才会进行初始化,而真正初始化的工作将从getBean方法 中展开

getBean向IOC容器获取Bean,判断此Bean是否可以实例化,然后创建Bean实例,并且封装成BeanWrapper返回

bean的生命周期,以及初始化前后进行处理

bean的生命周期分为三个阶段:bean创建—初始化----销毁的过程

在bean创建之后,我们可以在bean的初始化和销毁的前后对bean做一些处理,加入我们自己的逻辑,以下四种方式可以让我们在bean初始化和销毁的时候执行逻辑:

1)、指定初始化和销毁方法;通过@Bean指定init-method和destroy-method;
2)、通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
3)、可以使用JSR250;

@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作

4)、BeanPostProcessor【interface】:bean的后置处理器;

在bean初始化前后进行一些处理工作;
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作

调用顺序
BeanPostProcessor.postProcessBeforeInitialization

初始化:
对象创建完成,并赋值好,调用初始化方法。。。

BeanPostProcessor.postProcessAfterInitialization

销毁:

单实例:容器关闭的时候
多实例:容器不会管理这个bean;容器不会调用销毁方法;

bean实例化过程中,对信息进行处理:

如果你希望修改Bean的配置信息, 并且在Bean初始化的时候可以被使用到: 可以实现BeanFactoryPostProcessor接口,在相应回调方法中实现相应的逻辑。具体应用:配置Bean时占位符的替换,亦或是某些Bean的属性转换(电话号码中间几位的屏蔽),总而言之如果希望修改Bean配置信息,按照你希望的配置来进行初始化,就实现此接口。

如果你希望在Bean初始化完成之后对Bean有什么操作: 可以实现BeanPostProcessor接口。具体应用:AOP,AOP的原理其实是动态代理,实现AOP的核心类就实现了BeanPostProcessor接口,并且保证在Bean初始化(实例化与依赖注入)之后进行后处理,判断Bean是否应该被AOP,如果需要,则动态代理此Bean,返回代理后的proxy对象,IOC容器将使用proxy对象作为此Bean,完成AOP的操作。

如果你希望某个Bean按照你的方式进行初始化: 而不是IOC那些实例化、依赖注入、各种回调方法,那么你可以实现InstantiationAwareBeanPostProcessor,实现前处理方法来自定义Bean的初始化过程,返回实例即为此Bean,如果返回null的话IOC容器将继续初始化该Bean,所以可以判断某个Bean是自定义的初始化,剩下的Bean依然可以正常初始化。

如果你希望修改某个Bean的依赖注入属性,亦或是控制某个Bean不要进行依赖注入: 你可以实现InstantiationAwareBeanPostProcessor这个接口的依赖注入回调方法或是后处理方法。前者可以返回一个你修改后的属性封装对象,在接下来的处理中会针对你修改后的属性封装对象进行依赖注入,如果返回null将不会进行依赖注入。而后者只控制是否进行依赖注入,两者的区别与时序希望读者区分清楚,它们的共同点在都可以控制是否进行依赖注入,但侧重点不同。

如果你希望获取容器的某个资源:例如ClassLoader、BeanFactory、ApplicationContext、ResourceLoader等等一系列资源,你可以实现相对应的Aware接口,并且将类交给IOC容器管理,此类作为Bean将在你实现的Aware接口的对应方法中注入你所想要的属性。亦或是使用依赖注入的方式,也可以得到你想要的资源,原理在上面的3.3节其他的Aware接口中有提到,注册了对应的依赖:

如果你希望在Bean初始化完,执行一个类似初始化的方法:你可以实现InitializingBean接口,在对应方法中实现你想初始化的逻辑,时机是在Bean实例化、依赖注入、BeanPostProcessor的前处理之后,后处理之前将会执行的。
如果你希望注册监听器:实现ApplicationListener接口,并将类交给IOC容器管理,就可以自动注册监听器了,然后在对应方法中写具体通知方法之后需要做的事件逻辑。注册完监听器,就少不了发布事件,你可以在任意地方获取到上下文对象(方式有两种,上面都有提到),然后调用上下文对象的publishEvent方法即可发布事件,你所配置的监听器都会收到消息并执行你自定义的逻辑。

如果你希望伴随IOC容器有一个生命周期的动作:你可以让类实现Lifecycle接口,实现对应start/stop方法,其将会在容器初始化完成后执行start,在start中开始此Bean的生命周期的逻辑,达到一个生命周期的效果。

讲到这里,IOC容器的介绍也就告一段落了,我希望读者看到这里,能意识到IOC容器并不是解耦那么简单,因为有了IOC容器,才有AOP,才有各种各样灵活的处理,如果没有IOC容器去管理那些对象,我们需要做的事情可多太多太多了,IOC容器管理对象,极大简化了我们的开发过程。

原作者的文章链接:
https://blog.csdn.net/pzq915981048/article/details/106807316