面试还不知道BeanFactory和ApplicationContext的区别?

news/2024/10/30 23:14:37/

前言

接口 BeanFactory 和 ApplicationContext 都是用来从容器中获取 Spring beans
的,但是,他们二者有很大不同。


什么是 Spring Bean

之前一篇文章: Spring Bean生命周期 中有详细说明。

通常来说,Spring beans 就是被 Spring 容器所管理的 Java 对象。

package com.fhp;  
public class HelloWorld { private String message;  public void setMessage(String message){ this.message  = message; }  public void getMessage(){ System.out.println("My Message : " + message); } 
}

在基于 XML 的配置中, beans.xml 为 Spring 容器管理 bean 提供元数据。


什么是 Spring 容器

Spring 容器负责实例化,配置和装配 Spring beans,下面来看如何为 IoC 容器配置我们的 HelloWorld POJO。

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation = "http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id = "helloWorld" class = "com.fhp.HelloWorld"><property name = "message" value = "Hello World!"/></bean>
</beans>

现在,它已经被 Spring 容器管理了,接下来的问题是:我们怎样获取它?



ApplicationContext(应用上下文):继承BeanFactory接口,简单来说就是Spring中的容器,是Spring的一个更高级的容器。可以用来获取容器中的各种bean组件,注册监听事件,加载资源文件等功能。

BeanFactory:是Spring里面最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;

BeanFactory 接口:

这是一个用来访问 Spring 容器的 root 接口,要访问 Spring 容器,我们将使用 Spring 依赖注入功能,使用 BeanFactory 接口和它的子接口。

通常情况,BeanFactory 的实现是使用懒加载的方式,这意味着 beans 只有在我们通过 getBean() 方法直接调用它们时才进行实例化。

实现 BeanFactory 最常用的 API 是 XMLBeanFactory,如下图:

package fhp;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.xml.XmlBeanFactory; 
public class HelloWorldApp { public static void main(String[] args) { XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource("beans.xml")); HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");    obj.getMessage();    }
}


ApplicationContext 接口:

ApplicationContext 是 Spring 应用程序中的中央接口,用于向应用程序提供配置信息。它继承了 BeanFactory 接口,所以 ApplicationContext 包含 BeanFactory 的所有功能以及更多功能!它的主要功能是支持大型的业务应用的创建。

与 BeanFactory 懒加载的方式不同,它是预加载,所以,每一个 bean 都在 ApplicationContext 启动之后实例化。

package fhp;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.xml.XmlBeanFactory; 
public class HelloWorldApp{ public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld");    obj.getMessage();    }
}

特性:

  • Bean instantiation/wiring
  • Bean 的实例化/串联
  • 自动的 BeanPostProcessor 注册
  • 自动的 BeanFactoryPostProcessor 注册
  • 方便的 MessageSource 访问(i18n)
  • ApplicationEvent 的发布

1. 国际化(MessageSource)

<!- 资源国际化测试 ->
< beans>

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">        <property name="basenames">   <list>   <value>org/rjstudio/spring/properties/messages</value>   </list>   </property>   
</bean>   

< /beans>

org/rjstudio/spring/properties/messages 是指org.rjstudio.spring.proerties包下的以messages为主要名称的properties文件:

  • messages_en_US.properties
  • messages_zh_CN.properties
  • messages_zh_HK.properties

2. 访问资源,如URL和文件(ResourceLoader)

对资源文件(如:properties)进行存取操作的功能
ApplicationContext acxt =new ClassPathXmlApplicationContext("/applicationContext.xml");

通过虚拟路径来存取(classpath路径:存放.class等编译后文件的路径)
Resource resource = acxt.getResource(“classpath:messages_en_CN.properties”);

通过绝对路径存取资源文件
Resource resource = acxt.getResource(“file:F:/testwork/MySpring/src/messages_en_CN.properties”);

相对路径读取资源文件
Resource resource = acxt.getResource("/messages_en_CN.properties");


3. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

applicationContext.xml(主文件,包括JDBC配置,hibernate.cfg.xml,与所有的Service与DAO基类)

applicationContext-cache.xml(cache策略,包括hibernate的配置)

applicationContext-jmx.xml(JMX,调试hibernate的cache性能)

applicationContext-security.xml(acegi安全)

applicationContext-transaction.xml(事务)

moduleName-Service.xml

moduleName-dao.xml

< beans>
< import resource=“applicationContext-cache.xml”/>
< /beans>


4. 消息发送、响应机制(ApplicationEventPublisher)

ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。 如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。

两个重要成员
ApplicationEvent类:容器事件,必须由ApplicationContext发布;
ApplicationListener接口:监听器,可由容器中的任何监听器Bean担任。

例:
1.1. 定义容器事件 EmailEvent extends ApplicationEvent

1.2. 定义监听器 EmailNotifierListener implements ApplicationListener(容器事件的监听器类必须实现ApplicationListener接口)

1.3. 将监听器注入到spring容器

1.4. 测试:

public class SpringTest {

public static void main(String arg[]){  //读取Spring容器的配置文件  @SuppressWarnings("resource")  ApplicationContext applicationContext=new ClassPathXmlApplicationContext("application.xml");  //创建一个事件对象  EmailEvent emailEvent = new EmailEvent("hello Spring!", "cxg@126.com", "This is SpringApplicatoinContext test!");  //主动触发事件监视机制  applicationContext.publishEvent(emailEvent);  
}  

}


5. AOP(拦截器)

一般拦截器都是实现HandlerInterceptor,其中有三个方法preHandle、postHandle、afterCompletion

  1. preHandle:执行controller之前执行
  2. postHandle:执行完controller,return modelAndView之前执行,主要操作modelAndView的值
  3. afterCompletion:controller返回后执行

例:
1.1 注册拦截器,并且确定拦截器拦截哪些URL
< bean id=“validateSystemUserSessionInterceptor” class=“com.cherrypicks.appsdollar.cms.interceptor.ValidateSystemUserSessionInterceptor” />

<!-- Interceptors -->  
<mvc:interceptors>  <mvc:interceptor>  <mvc:mapping path="/**" />  <mvc:exclude-mapping path="/login" />  <mvc:exclude-mapping path="/logout" />  <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->   <ref bean="validateSystemUserSessionInterceptor"  />  </mvc:interceptor>  
</mvc:interceptors>  

1.2. 定义拦截器实现类

public class ValidateSystemUserSessionInterceptor extends HandlerInterceptorAdapter {

private final Log logger = LogFactory.getLog(this.getClass());  @Autowired  
private CmsUserSessionService userSessionService;  @Override  
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler)  throws Exception {  logger.debug("ValidateUserSessionInterceptor.preHandle run....");   final String userIdStr = request.getParameter(Constants.USERID);  final String sessionId = request.getParameter(Constants.SESSIONID);  if (!StringUtils.isNotBlank(userIdStr) || !StringUtils.isNotBlank(sessionId)) {  throw new InvalidUserSessionException(  "Invalid user session. userId[" + userIdStr + "], sessionId[" + sessionId + "]");  }  final Long userId = Long.parseLong(userIdStr);  // validate userId and sessionId  if (!userSessionService.validateUserSession(userId, sessionId)) {  throw new InvalidUserSessionException(  "Invalid user session. userId[" + userId + "], sessionId[" + sessionId + "]");  }  return true;  
}

1.3. 测试

public static void main(final String[] args) {

    final String i = "a";  System.out.println(StringUtils.isNotBlank(i));  
}

小结:

ApplicationContext在启动的时候就把所有的Bean全部实例化。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;

延迟实例化的优点:(BeanFactory)

  1. 应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;

不延迟实例化的优点: (ApplicationContext)

  1. 所有的Bean在启动的时候都加载,系统运行的速度快;
  2. 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
  3. 建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)

SpringBoot中获取ApplicationContext的三种方式:

一、 直接使用Autowired注入
在这里插入图片描述

二、利用 spring4.3 的新特性
在这里插入图片描述

三、实现spring提供的接口 ApplicationContextAware
在这里插入图片描述


总结

ApplicationContext 包含 BeanFactory 的所有特性,通常推荐使用前者。但是也有一些限制情形,比如移动应用内存消耗比较严苛,在那些情景中,使用更轻量级的 BeanFactory 是更合理的。然而,在大多数企业级的应用中,ApplicationContext 是你的首选。


http://www.ppmy.cn/news/463976.html

相关文章

孕期出轨的男人值不值得原谅

&#xfeff;&#xfeff; 晓芸跟老公结婚十多年&#xff0c;期间经历了几次习惯性流产&#xff0c;前些年的一次宫外孕大出血险些要了她的命&#xff0c;为了要个孩子&#xff0c;她做过三次试管婴儿&#xff0c;但最终都失败了。原本对于做妈妈这事已经不再抱什么幻想的她&am…

分手快乐---(哪个更好呢)

我无法帮你预言 为你祈祷有没有用 可是我多么不舍朋友过得那么痛苦 爱可以重新选择只要你过得幸福 如果他总是忘记未来 你何苦非把心放在他手中 好音乐让你满足想撑过你心口里的空 你却想有人了解藏在心底那最无助的通 你说你勇敢面对 未来的全新生活 这宴席已经散了 剩…

新房装修材料避坑分享

第一次装修怕被坑,雅静说选哪些品牌的材料才能避坑 1,水管选伟星,日丰,联塑,因为水管的核心是质保, 要选水管管件和人工焊接点,双重质保的 2,电线选正泰,德力西,公牛,熊猫,一定要选国际带有3C认证的 3,水泥选海螺,华润,中联,水泥一定要用新日期的,正常的用325,有条件的话用425 …

史上踩坑最多的SpringBoot整合Mybatis

自由不是你想做什么就能做什么&#xff0c;而是你不想做什么就可以不做什么。 目录 前言数据库部分整合部分一波三折数据库驱动再次配置映射文件再配数据源回溯章节 前言 关于如何搭建SpringBoot工程以及开启Web功能&#xff0c; 可以查看我的这篇博客&#xff1a;用Spring Ini…

跟父母还是要保持一定的距离感

背景 不知你有没有亲身经历过&#xff0c;或者见过身边的人正在经历下面这些场景&#xff1a; 自己交了男/女朋友&#xff0c;父母感觉不太好时劝分手结婚前&#xff0c;父母对另一半的询问或考验让对方难堪结婚后&#xff0c;父母经常帮忙处理家庭事务&#xff08;打扫卫生&a…

死磕Spring系列:Bean实例化原理

本文将从源码的角度来分析SpringBean的创建过程 1. BeanDefinition 大家都知道&#xff0c;在Spring IOC启动时&#xff0c;会扫描类的信息&#xff0c;将相关信息封装为BeanDefinition存入到beanDefinitionMap中&#xff0c;后续用其中的描述信息来生成bean。 2. getBean 首…

不分手,好吗?

你提出分手&#xff0c;显得那么平静&#xff0c;不带一丝惋惜。  当你来到我的身旁&#xff0c;我发现&#xff0c;平静的你是如此的美丽&#xff01;真的想抱住你&#xff0c;吻你……但我不能&#xff01;  你知道吗&#xff0c;你的这份美丽让我凭添了许多痛苦&#xf…

这个, ..., 男方也太背了吧, 尽碰上极品女方...

发信人: jungleford (風淸揚╬孤城斩菜羊), 信区: Joke 标 题: 我生活在上海&#xff0c;我相亲无数次&#xff0c;那些极品女方父母 (转载) 发信站: 水木社区 (Sun Aug 22 20:58:53 2010), 站内 【 以下文字转载自 Shanghai 讨论区 】 发信人: adi (杨过), 信区: Shanghai 标…