BeanFactory和ApplicationContext的区别
面试官:你知道BeanFactory和ApplicationContext到底有什么区别吗?
面试者:
1、BeanFactory:是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能;
// 仅保留重接口,删除了一些重载接口
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
}
2、ApplicationContext:应用上下文,继承BeanFactory接口,它是Spring的一个功能丰富的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
面试官微微一笑:那你知道在Spring环境中,如果采用@Autowired的方式对BeanFactory和ApplicationContext进行赋值,结果是true还是flase?这里我用代码解释一下问题,创建一个ApplicaitonContextEqulesBeanFactory 类实现ApplicationContextAware 接口
@Component
public class ApplicaitonContextEqulesBeanFactory implements ApplicationContextAware {
private ApplicationContext applicationContextAware;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private BeanFactory beanFactory;
public ApplicationContext getApplicationContextAware() {
return applicationContextAware;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContextAware = applicationContext;
}
}
创建测试类
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
ApplicaitonContextEqulesBeanFactory applicaitonContextEqulesBeanFactory= (ApplicaitonContextEqulesBeanFactory) annotationConfigApplicationContext.getBean("applicaitonContextEqulesBeanFactory");
// BeanFactory == AnnotationConfigApplicationContext
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()== annotationConfigApplicationContext);
// AnnotationConfigApplicationContext == ApplicaitonContext
System.out.println(annotationConfigApplicationContext == applicaitonContextEqulesBeanFactory.getApplicationContext());
// ApplicaitonContext == ApplicaitonContextaware
System.out.println(applicaitonContextEqulesBeanFactory.getApplicationContext()==
applicaitonContextEqulesBeanFactory.getApplicationContextAware());
// BeanFactory == ApplicaitonContext
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
applicaitonContextEqulesBeanFactory.getApplicationContext());
// BeanFactory == AnnotationConfigApplicationContext.getBeanFactory
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
annotationConfigApplicationContext.getBeanFactory());
// BeanFactory == ApplicationContext.getBeanFactory
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
applicaitonContextEqulesBeanFactory.getApplicationContext().getAutowireCapableBeanFactory());
// 通过查找的方式获取 BeanFactory
//BeanFactory beanFactory=annotationConfigApplicationContext.getBean(BeanFactory.class);
}
}
我们来看运行结果:
看到第一个结果false 对应的是BeanFactory == AnnotationConfigApplicationContext,这个BeanFactory 是通过@Autowired赋值,我们再来看第二个AnnotationConfigApplicationContext == ApplicaitonContext,这里结果为true,第三个ApplicaitonContext == ApplicaitonContextaware也为true,第四个 BeanFactory == ApplicaitonContext为false,第五个AnnotationConfigApplicationContext.getBeanFactory == BeanFactory 为true。最后一个ApplicationContext.getBeanFactory == BeanFactory 为true,我们可以得出结论,AnnotationConfigApplicationContext就是我们的ApplicaitionContext的来源,而且实现了ApplicationContextAware 的数据来源也是AnnotationConfigApplicationContext,注意关键点来了BeanFactory不等于ApplicationContext,而是等于ApplicationContext.getAutowireCapableBeanFactory,这是为什么呢?我们看看ApplicationContext.getAutowireCapableBeanFactory方法
可以看到这里我们同时验证了ApplicationContext对象==AnnotationConfigApplicationContext ,在上个Spring环境的章节,笔者提到,BeanFactory只是Spring环境的一部分,而这个BeanFactory在一开始就在Spring内部创建了,所以我们这里的this.BeanFactory是内建的,因此回到我们的主题BeanFactory和ApplicationContext的区别,ApplicationContext虽然继承了BeanFactory,通过上面测试的结果就可以发现它们两者并不相同,而在ApplicationContext的子实现中有一个内部的BeanFactory属性,所以在ApplicationContext对工厂操作的真正角色就是这个BeanFactory,那么为什么我们注入BeanFactory和ApplicationContext他们的数据源不一样呢?这里我们先看一段代码
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext=
new AnnotationConfigApplicationContext(AppConfig.class);
ApplicaitonContextEqulesBeanFactory applicaitonContextEqulesBeanFactory =
(ApplicaitonContextEqulesBeanFactory) annotationConfigApplicationContext.getBean("applicaitonContextEqulesBeanFactory");
// BeanFactory == AnnotationConfigApplicationContext
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
annotationConfigApplicationContext);
// AnnotationConfigApplicationContext == ApplicaitonContext
System.out.println(annotationConfigApplicationContext ==
applicaitonContextEqulesBeanFactory.getApplicationContext());
// ApplicaitonContext == ApplicaitonContextaware
System.out.println(applicaitonContextEqulesBeanFactory.getApplicationContext()==
applicaitonContextEqulesBeanFactory.getApplicationContextAware());
// BeanFactory == ApplicaitonContext
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
applicaitonContextEqulesBeanFactory.getApplicationContext());
// BeanFactory == AnnotationConfigApplicationContext.getBeanFactory
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
annotationConfigApplicationContext.getBeanFactory());
// BeanFactory == ApplicationContext.getBeanFactory
System.out.println(applicaitonContextEqulesBeanFactory.getBeanFactory()==
applicaitonContextEqulesBeanFactory.getApplicationContext().getAutowireCapableBeanFactory());
// 通过查找的方式获取 BeanFactory
BeanFactory beanFactory=annotationConfigApplicationContext.getBean(BeanFactory.class);
}
}
最后一行我们添加了 BeanFactory beanFactory=annotationConfigApplicationContext.getBean(BeanFactory.class);我们先看执行结果
看到这里出现了异常,为什么会出现异常?通常来说我们依赖注入的数据来源都是工厂获取,而我们通过getBean的方式也是从工厂得到的,依赖注入的数据来源和依赖查找的方式是来自于不同的数据源,这不能说完全不同的数据源,只是Spring对一些关键类提供了特殊的额外空间来给予依赖注入,那么这里的注入来源来自哪里呢?看下图:
仔细看这几个value值就可以得出结论为什么注入的BeanFactory和Appllication不同了。