Spring源码级别分析@Lazy注解和FactoryBean接口

@Lazy注解--懒加载分析及FactoryBean接口

示例

代码

@Configuration
@Import(value = {CompentC.class,TulingImportSelect.class,TulingImportBeanfinitionRegister.class})
@ComponentScan(basePackages = {"com.tuling.parsebeandefinition"})
public class MainConfig {

	@Bean
	@Lazy
	public CompentD compentD() {
		return new CompentD();
	}
}

当我们的实体类加上懒加载注解后,不会自动装配到IOC容器里。也就是1级缓存池中不会有

原因

finishBeanFactoryInitialization(beanFactory)
//冻结所有的 bean 定义 , 说明注册的 bean 定义将不被修改或任何进一步的处理
beanFactory.freezeConfiguration();
//实例化剩余的单实例bean
beanFactory.preInstantiateSingletons();

重点来了,面试官最爱在这问的
在这里插入图片描述

所以我们知道了懒加载的bean只有当被getBean调用的时候才会放入IOC容器的一级缓存池中。

FactoryBean

FactoryBean是个接口,实现这个接口必须实现他的方法,最重要的就是getObject

我们可以把实现这个接口,理解为偷梁换柱

public class MainClass {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = 
		   new AnnotationConfigApplicationContext(MainConfig.class);
		CompentD compentD =(CompentD) ctx.getBean("compentA");
		System.out.println(compentD);
	}
}
@Component
public class CompentA implements FactoryBean {


	public CompentA() {
		System.out.println("compentA.....的构造方法");
	}

	@Override
	public Object getObject() throws Exception {
		return new CompentD();
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}
}

来看doGetBean方法的getObjectForBeanInstance
name 以 & 开头,但 beanInstance 却不是 FactoryBean,则认为有问题。

if (BeanFactoryUtils.isFactoryDereference(name)) {
	if (beanInstance instanceof NullBean) {
		return beanInstance;
	}
	if (!(beanInstance instanceof FactoryBean)) {
		throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
	}
}

如果上面的判断通过了,表明 beanInstance 可能是一个普通的 bean,也可能是一个FactoryBean。

如果是一个普通的 bean,这里直接返回 beanInstance 即可。

如果是FactoryBean,则要调用工厂方法生成一个 bean 实例。

//在这里会调用getObject()
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
factory.getObject();

最后来到我们实体类的在这里插入图片描述

总结

最后会在getBean的时候,经过一系列的判断,

把实体类转为一个FactoryBean的泛型

FactoryBean<?> factory = (FactoryBean<?>) beanInstance;

实现了FactoryBean接口的类,会调用getObject方法返回最终的对象。

思考

怎么样把实现了FactoryBean接口的类,通过getBean之后,不会走getObject方法

AnnotationConfigApplicationContext ctx = 
      new AnnotationConfigApplicationContext(MainConfig.class);
CompentA compentA =(CompentA) ctx.getBean("&compentA");
System.out.println(compentA);

最后可以猜猜这段代码运行结果

public static void main(String[] args) {
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
	CompentA compentA =(CompentA) ctx.getBean("&compentA");
	System.out.println(compentA);
	CompentD compentd =(CompentD) ctx.getBean("compentA");
	System.out.println(compentd);
}
@Component
public class CompentA implements FactoryBean {


	public CompentA() {
		System.out.println("compentA.....的构造方法");
	}

	@Override
	public Object getObject() throws Exception {
		return new CompentD();
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值