BeanFactory和ApplicationContext的区别
面试官:你知道 BeanFactory和ApplicationContext到底有什么区别吗? 面试者: 1、BeanFactory: 是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能;// 仅保留重接口,删除了一些重载接口public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; ObjectProvidergetBeanProvider(Class 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
接口
@Componentpublic 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 == AnnotationConfigAppli cationContext,这个 BeanFactory 是通过 @Autowired赋值,我们再来看第二个 AnnotationConfigApplicationContext == ApplicaitonContext,这里结果为true,第三个 ApplicaitonContext == ApplicaitonContextaware也为true,第四个 BeanFactory == ApplicaitonContext为false,第五个 AnnotationConfigApplicationContext.getBeanFactory == BeanFactory 为true。最后一个 ApplicationContext.getBeanFactory == BeanFactory 为true,我们可以得出结论, AnnotationConfigAppli cationContext就是我们的ApplicaitionContext的来源,而且实现了 ApplicationContextAware 的数据来源也是 AnnotationConfigAppli cationContext,注意关键点来了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不同了。