- BeanFactory和ApplicationContext的区别
描述
是 Spring 里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
应用上下文,继承BeanFactory接口,它是 Spring 的一各更高级的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如 URL 和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的 web 层
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)
两者装载 bean 的区别
BeanFactory在启动的时候不会去实例化 Bean,中有从容器中拿 Bean 的时候才会去实例化;
ApplicationContext在启动的时候就把所有的 Bean 全部实例化了。它还可以为 Bean 配置 lazy-init=true 来让 Bean 延迟实例化;
我们该用BeanFactory还是 ApplicationContent
延迟实例化的优点:(BeanFactory)
应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
不延迟实例化的优点: (ApplicationContext)
1. 所有的 Bean 在启动的时候都加载,系统运行的速度快;
2. 在启动的时候所有的 Bean 都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
3. 建议 web 应用,在启动的时候就把所有的 Bean 都加载了。(把费时的操作放到系统启动中完成)
spring 国际化例子(MessageSource)
1. 在 xml 中配置 messageSource
Xml 代码
- <?xml version=”1.0″ encoding=”UTF-8″?>
- <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>
- <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>
2. “org/rjstudio/spring/properties/messages”,是指 org.rjstudio.spring.proerties 包下的以 messages 为主要名称的 properties 文件
文件如下:
messages_en_US.properties
messages_zh_CN.properties
messages_zh_HK.properties
3. 取值的时候是通过ApplicationContext.getMessage(),拿到对应语言的内容
Java 代码
- public class MessageTest {
- public static void main(String[] args) {
- ApplicationContext ctx = new ClassPathXmlApplicationContext(“messages.xml”);
- Object[] arg = new Object[] { “Erica”, Calendar.getInstance().getTime() };
- String msg = ctx.getMessage(“userinfo”, arg,Locale.CHINA);
- System.out.println(“Message is ===> ” + msg);
- }
- }
spring 访问资源(ResourceLoader)
这是 spring 对资源文件(如:properties)进行存取操作的功能
ApplicationContext acxt =new ClassPathXmlApplicationContext(“/applicationContext.xml”);
1.通过虚拟路径来存取。当资源位于 CLASSPATH 路径下时,可以采用这种方式来存取。
Resource resource = acxt.getResource(“classpath:messages_en_CN.properties”);
2.通过绝对路径存取资源文件。
Resource resource = acxt.getResource(“file:F:/testwork/MySpring/src/messages_en_CN.properties”);
3.相对路径读取资源文件。
Resource resource = acxt.getResource(“/messages_en_CN.properties”);
Resource 常用的方法:
getFilename() : 获得文件名称
contentLength() : 获得文件大小
createRelative(path) : 在资源的相对地址上创建新文件
exists() : 是否存在
getFile() : 获得 Java 提供的 File 对象
getInputStream() : 获得文件的流
spring 载入多个上下文
不同项目使用不同分模块策略,spring 配置文件分为
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
两种方法配置
1.可以在 applicationContext.xml 文件中引用
<beans></beans>标记之间引入其他 applicationContext.xml
<beans>
<import resource=”applicationContext-cache.xml”/>
</beans>
2.或者在 web.xml 文件中引用
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INF/classes/applicationContext-security.xml
,WEB-INF/classes/applicationContext-dao.xml
,WEB-INF/classes/applicationContext-Service.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
spring 事件机制(订阅发布模式 == 观察者模式)
ApplicationContext 事件机制是观察者设计模式的 实现,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 事件处理。 如果容器中有一个 ApplicationListener Bean,每当 ApplicationContext 发布 ApplicationEvent 时,ApplicationListener Bean 将自动被触发。
两个重要成员
ApplicationEvent:容器事件,必须由 ApplicationContext 发布;
ApplicationListener:监听器,可由容器中的任何监听器 Bean 担任。
1. 定义容器事件
Java 代码
- package com.cxg.test.springPlatfrom;
- import org.springframework.context.ApplicationEvent;
- /**
- * Title: email 之事件类
- * EmailEvent 类继承了 ApplicationEvent 类,除此之外,它就是一个普通的 Java 类
- * Description: dataPlatfrom
- * @author: xg.chen
- * @date:2016 年 8 月 24 日
- */
- public class EmailEvent extends ApplicationEvent{
- private static final long serialVersionUID = 1L;
- //属性
- private String address;
- private String text;
- //构造方法
- public EmailEvent(Object source) {
- super(source);
- }
- public EmailEvent(Object source, String address, String text) {
- super(source);
- this.address = address;
- this.text = text;
- }
- //getter 和 setter 设置
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public String getText() {
- return text;
- }
- public void setText(String text) {
- this.text = text;
- }
- }
2. 定义监听器
Java 代码
- package com.cxg.test.springPlatfrom;
- import org.springframework.context.ApplicationEvent;
- import org.springframework.context.ApplicationListener;
- /**
- * Title: email 之监听类
- * 容器事件的监听器类必须实现 ApplicationListener 接口,实现该接口就必须实现
- * Description: dataPlatfrom
- * @author: xg.chen
- * @date:2016 年 8 月 24 日
- */
- public class EmailNotifier implements ApplicationListener<ApplicationEvent>{
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- if(event instanceof EmailEvent){
- EmailEvent emailEvent = (EmailEvent) event;
- System.out.println(“email’s address:”+emailEvent.getAddress());
- System.out.println(“email’s text:”+emailEvent.getText());
- } else {
- System.out.println(“the Spring’s event:”+event);
- }
- }
- }
3. 将监听器注入到 spring 容器
Xml 代码
- <!– 配置事件监听 –>
- <bean class=”com.cxg.test.springPlatfrom.EmailNotifier” />
4. 测试
Java 代码
- package com.cxg.test.springPlatfrom;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /**
- * Title: Spring 的 ApplicationContexet 单元成测试
- * Description: dataPlatfrom
- * @author: xg.chen
- * @date:2016 年 8 月 24 日
- */
- 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);
- }
- }
spring 的 AOP(常用的是拦截器)
一般拦截器都是实现 HandlerInterceptor,其中有三个方法preHandle、postHandle、afterCompletion
1. preHandle:执行 controller 之前执行
2. postHandle:执行完 controller,return modelAndView 之前执行,主要操作 modelAndView 的值
3. afterCompletion:controller 返回后执行
实现步骤:
1. 注册拦截器,并且确定拦截器拦截哪些 URL
Xml 代码
- <!– Check Session –>
- <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>
- <!– SpringMVC.end} –>
2. 定义拦截器实现类
Java 代码
- package com.cherrypicks.appsdollar.cms.interceptor;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.commons.lang.StringUtils;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
- import com.cherrypicks.appsdollar.common.constant.Constants;
- import com.cherrypicks.appsdollar.common.exception.InvalidUserSessionException;
- import com.cherrypicks.appsdollar.service.cms.CmsUserSessionService;
- 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;
- }
- public static void main(final String[] args) {
- final String i = “a”;
- System.out.println(StringUtils.isNotBlank(i));
- }
- }