spring版本
bean的作用域
spring四种实例化bean的方式
关于bean别名
FactoryBean
bean循环依赖
BeanPostProcessor
spring的发展:
第一阶段,spring1.x阶段所有的bean都是在xml中配置。
第二阶段,spring2.x阶段出现了基于注解的bean配置。
第三阶段,spring3.x阶段使用java配置类配置bean。
当前spring4.x阶段,推荐基于spring boot+java配置类。
通过注解@Scope可以指定bean的作用域。bean有5种作用域:
1、Singleton单利:整个spring容器中只有一个实例 ,默认就是单利
2、protoType:每次调用新建一个实例。
3、request:在web应用中,每个请求创建一个实例
4、session:在web应用中,每个回话创建一个实例
5、globalSession:这个只在portal应用中存在。
第一种:使用构造器实例化Bean。
这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式创建Bean。
第二种:使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean.
第三种:使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样。
第四种:用 setter 方式.这种方式,只要写上对应的set、get方法,然后再bean.xml文件中利用property注入值即可。
每个 Bean 在 Spring 容器中都有一个唯一的名字(beanName)和 0 个或多个别名(aliases)。
我们从 Spring 容器中获取 Bean 的时候,可以根据 beanName,也可以通过别名。
beanFactory.getBean("beanName or alias");
在配置
<bean id="messageService" name="m1, m2, m3" class="com.javadoop.example.MessageServiceImpl">
以上配置的结果就是:beanName 为 messageService,别名有 3 个,分别为 m1、m2、m3。
<bean name="m1, m2, m3" class="com.javadoop.example.MessageServiceImpl" />
以上配置的结果就是:beanName 为 m1,别名有 2 个,分别为 m2、m3。
<bean class="com.javadoop.example.MessageServiceImpl">
以上配置的结果就是beanName 为:com.javadoop.example.MessageServiceImpl#0,别名 1 个,为: com.javadoop.example.MessageServiceImpl
<bean id="messageService" class="com.javadoop.example.MessageServiceImpl">
以上配置的结果就是:beanName 为 messageService,没有别名。
FactoryBean 适用于 Bean 的创建过程比较复杂的场景,比如数据库连接池的创建。
我们假设现在需要创建一个 Person 的 Bean,首先我们需要一个 Car 的实例,我们这里假设 Car 的实例创建很麻烦,那么我们可以把创建 Car 的复杂过程包装起来.
public class Person {
private Car car ;
private void setCar(Car car){ this.car = car; }
}
public class MyCarFactoryBean implements FactoryBean<Car>{
private String make;
private int year ;
public void setMake(String m){ this.make =m ; }
public void setYear(int y){ this.year = y; }
public Car getObject(){
// 这里我们假设 Car 的实例化过程非常复杂,反正就不是几行代码可以写完的那种
CarBuilder cb = CarBuilder.car();
if(year!=0) cb.setYear(this.year);
if(StringUtils.hasText(this.make)) cb.setMake( this.make );
return cb.factory();
}
public Class<Car> getObjectType() { return Car.class ; }
public boolean isSingleton() { return false; }
}
<bean class = "com.javadoop.MyCarFactoryBean" id = "car">
<property name = "make" value ="Honda"/>
<property name = "year" value ="1984"/>
</bean>
<bean class = "com.javadoop.Person" id = "josh">
<property name = "car" ref = "car"/>
</bean>
在来看一个通过java config方式配置bean的例子。
@Configuration
public class CarConfiguration {
@Bean
public MyCarFactoryBean carFactoryBean(){
MyCarFactoryBean cfb = new MyCarFactoryBean();
cfb.setMake("Honda");
cfb.setYear(1984);
return cfb;
}
@Bean
public Person aPerson(){
Person person = new Person();
// 注意这里的不同
person.setCar(carFactoryBean().getObject());
return person;
}
}
这个时候,其实我们的思路也很简单,把 MyCarFactoryBean 看成是一个简单的 Bean 就可以了,不必理会什么 FactoryBean,它是不是 FactoryBean 和我们没关系。
循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
Spring中循环依赖场景有:
(1)构造器的循环依赖
(2)field属性的循环依赖
其中,构造器的循环依赖问题无法解决,只能拋出BeanCurrentlyInCreationException异常,在解决属性循环依赖时,spring采用的是提前暴露对象的方法。
构造器循环依赖:场景1
public class A{
public A(B b){
}
}
public class B{
public B(A a){
}
}
非构造器依赖:场景2
public class A{
@Autowired
B b;
}
public class B{
@Autowired
A a;
}
或者:场景3
public class A{
public A(B b){
}
}
public class B{
@Autowired
A a;
}
ioc bean创建过程如下:
createBeanInstance:实例化bean(执行的是构造器)。
populateBean:给bean初始化值(执行bean依赖的属性)
spring是通过三级缓存解决循环依赖:
singletonFactories(三级) : 单例对象工厂的cache
earlySingletonObjects (二级):提前暴光的单例对象的Cache (执行了构造器,但是未初始化)
singletonObjects(一级):单例对象的cache(一个完整的bean对象)
先分析以下非构造器循环依赖接是如何解决的:上面场景2的代码
1、实例化A,执行A的createBeanInstance,将A添加到三级缓存,然后执行A的populateBean方法,发现依赖B,从一、二、三级缓存中都没有B。
2、开始创建B,执行B的createBeanInstance,将B添加到三级缓存,然后执行B的populateBean方法,返现依赖A,从三级缓存中发现了A(虽然是不完整的A,但是也可以用于bean依赖),B的初始化完毕。
3、回到A继续,A可以拿到完整的B,流程结束。
方法createBeanInstance就是执行构造器的,所以只有构造器能成功执行对象才会被添加到三级缓存,而构造器依赖是在构造器中发生的依赖,对象还未被添加到三级缓存,所以构造器依赖无法解决。
spring构造器依赖抛异常是如何实现的呢?
Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
Spring容器先创建单例A,A依赖B,然后将A放在“当前创建Bean池”中,此时创建B,B依赖C ,然后将B放在“当前创建Bean池”中,此时创建C,C又依赖A, 但是,此时A已经在池中,所以会报错,,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,(初始化完的Bean会从池中移除)
源码包含几个地方:
1、在createBeanInstance后设置三级缓存。
2、在populateBean初始化对象之前通过autowireByName循环调用getBean方法,从三级缓存中获取依赖对象。
具体代码位置https://github.com/sunyanhui123/note/issues/56#issue-422578341中都有注释说明。
名字叫做后置处理器,spring提供的扩展接口。
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
容器的每个Bean在调用初始化方法之前,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。
如何使用?
BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization。
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
super();
System.out.println("这是BeanPostProcessor实现类构造器!!");
}
@Override
public Object postProcessAfterInitialization(Object bean, String arg1)
throws BeansException {
System.out.println("bean处理器:bean创建之后..");
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String arg1)
throws BeansException {
System.out.println("bean处理器:bean创建之前..");
return bean;
}
}
要使用BeanPostProcessor回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory和ApplicationContext容器的注册方式不大一样:若使用BeanFactory,则必须要显示的调用其addBeanPostProcessor()方法进行注册,参数为BeanPostProcessor实现类的实例;如果是使用ApplicationContext,那么容器会在配置文件在中自动寻找实现了BeanPostProcessor接口的Bean,然后自动注册,我们要做的只是配置一个BeanPostProcessor实现类的Bean就可以了。
入口:refresh方法中的registerBeanPostProcessors方法。
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
/**
*1.代码走到了这里的时候其实 BeanDefinition数据已经被加载了,只是bean还没有被实例化
所以这个是去容器里面找到所有类型为BeanPostProcessor的beanName
*/
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//记录所有的beanProcessor数量,在这之前也可能注册了一部分Spring内部的BeanPostProcessors接口,例如:ApplicationContextAwareProcessor
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//貌似只是记录日志用的
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 优先级最高的BeanPostProcessors,这类最先调用;需要实现PriorityOrdered接口
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
//内部BeanPostProcessors
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
//继承了Ordered接口,优先级比上面低一点
List<String> orderedPostProcessorNames = new ArrayList<String>();
//这就是普通的了,优先级最低
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
//下面的这些代码就是遍历所有postProcessorNames,按优先级排序;类型PriorityOrdered>Ordered>普通;在这个类型基础上,还要对他们的order属性就行排序;
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);//入口
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);//入口
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
//这里要注意一下了,看到没有,这个时候已经调用了getBean来生成实例对象了;
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);//入口
// 排序
sortPostProcessors(beanFactory, internalPostProcessors);
//注册
registerBeanPostProcessors(beanFactory, internalPostProcessors);//入口
// 加入ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
/**
* 注册 BeanPostProcessor beans.
* 容器中beanPostProcessors是一个ArrayList来持有这些BeanPostProcessors
*/
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
//将是否 hasInstantiationAwareBeanPostProcessors设置为true
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}
总结一下上面流程:
1、Spring加载完了所有的BeanDefinition之后,找到所有类型为BeanPostProcessors的BeanDefinition对象;
2、根据得到的类型是否实现了PriorityOrdered>Ordered>无继承Ordered;在这个优先级基础上,每个实现了Ordered接口的(PriorityOrdered也实现了Ordered)都有一个order属性,还要根据order来进行排序。
3、将BeanPostProcessors实例都添加到BeanFactory中。
到此所有的后置处理器都已经添加到容器中了,那么具体是在什么地方使用的呢?
调用的地方比较多,还有很多Spring内部的接口,还有其他的比如MergedBeanDefinitionPostProcessor等也继承了BeanPostProcessors接口的扩展接口,
我们这里先只分析我们自己继承这个BeanPostProcessors接口的实例是什么时候被调用的;
答案是initializeBean方法。
回顾一下bean创建过程的三个重要方法:
1、createBeanInstance:实例化bean
2、populateBean :给bean设置值(包括依赖注入的bean)
3、initializeBean:各种回调
第三个方法负责回调就是执行BeanPostProcessors的地方。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//省略....
if (mbd == null || !mbd.isSynthetic()) {
//初始化之前
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {//初始化
invokeInitMethods(beanName, wrappedBean, mbd);
}
//初始化之后
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
//省略...
}
//注意 每一个实例对象触发这个的时候 都是执行所有的BeanPostProcessors实例对象
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
//这里是循环
// result =BeanPostProcessor调用执行方法;返回的对象还是result,
// 只是有可能被某个BeanPostProcessor加强了
// beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
所以只要调用getBean方法,就会执行BeanPostProcessors。
原文:https://www.cnblogs.com/yanhui007/p/12595474.html