《Spring揭秘》第五章 读书笔记 —— ApplicationContext
来源:互联网 发布:.com.hk域名注册 编辑:程序博客网 时间:2024/05/18 01:03
在第三章中已经提到了,ApplicationContext除了和BeanFactory共同实现了两个接口,但是ApplicationContext有另外实现了其他三个接口,分别是FileSystemXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext,这也就意味着ApplicationContext在功能上面有了扩展,将其当做是BeanFactory的升级版也是可以的
- 统一资源加载策略
spring框架中使用org.springframework.core.io.Resource作为所有的资源文件访问的接口,有几种不同的使用场景的接口:
· ByteArrayResource 该实现根据字节数组的数据,构造相应的ByteArrayInputStream并返回
· ClassPathResource 从Java应用程序的ClassPath中加载具体资源并封装,使用指定的类加载器或者给定的类进行资源加载
· URLResource 通过java.net.URL进行具体的资源加载
· InputStreamResource 较为少用的资源加载Resource的实现类,一般可用ByteArrayResource代替
public interface Resource extends InputStreamSource { boolean exists(); boolean isOpen(); URL getURL() throws IOException; File getFile() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }public interface InputStreamSource { InputStream getInputStream() throws IOException;}
在Resource中定义了七个方法,可以用来对资源文件的查找、访问
ResourceLoader,“更加广义的URL”
- DefaultResourceLoader
ResourceLoader的默认的资源加载机制,默认加载逻辑:
(1) 首先查询资源路径是否是以“classpath:”开头,如果是,就尝试构造ClassPathLoader类型资源返回
(2) 否则,常使用URL定位资源文件位置,如果没有抛出MalformedURLException,就会构造URLResource类型的资源并返回;如果无法找到资源文件,则需要委派getResourceByPath(String xx)方法来定位
- FileSystemResourceLoader
为了避免DefaultResourceLoader在getResourceByPath(String xx)不恰当的处理,FileSystemResourceLoader继承了DefaultResourceLoader并重写了getResourceByPath(String xx)方法,返回FileSystemResourceLoader类型资源,重写方法:
public void testResourceTypesWithFileSystemResourceLoader(){ ResourceLoader resourceLoader = new FileSystemResourceLoader(); Resource fileResource = resourceLoader.getResource("D:/spring21site/README"); assertTrue(fileResource instanceof FileSystemResource); assertTrue(fileResource.exists()); Resource urlResource = resourceLoader.getResource("file:D:/spring21site/README"); assertTrue(urlResource instanceof UrlResource); }
覆写getResourceByPath(String xx)方法的逻辑,以改变DefaultResourceLoader的默认资源加载行为,最终从文件系统中加载并返回FileSystemResource类型的资源。
ResourcePatternResolver——批量查找的ResourceLoader
ResourceLoader是加载一个资源文件,返回一个资源实例,而ResourcePatternResolver是可以批量查找资源文件,返回多个资源实例,ResourcePatternResolver的接口定义:
public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; Resource[] getResources(String locationPattern) throws IOException;}
从接口定义中可以看出,ResourcePatternResolver引入了 Resource[] getResources(String locationPattern),也就是说匹配过程中将资源文件都存入这个数组中,返回的是资源文件夹,并且有了classpath*:的新定义。但是加载资源文件的方式是一致的
各个接口之间的关系
- ApplicationContext与ResourceLoader
所有的ApplicationContext实现类会直接或者间接地继承AbstractApplicationContext,AbstractApplicationContext继承了DefaultResourceLoader,所以说ApplicationContext的实现类可以直接查找加载资源文件- 可以通过ApplicationContext的实现类加载Spring支持的Resource类型
- 如果某个bean需要依赖特定的ResourceLoader查找资源,可以为其注入ResourceLoader的具体实现
- 国际化信息支持
JavaSE对于国际化有了很好的支持,涉及的两个类是Local和ResourceBundle,都是util包中的类
(1)Local用于代表不同的国家和地区,例如:Local.CHINA代表中国
(2)ResourceBundle用来保存特定于某个Locale的信息(可以是String类型信息,也可以是任何类型的对象),相应的有properties文件,我们就可以通过ResourceBundle的getBundle(String baseName, Locale locale)方法取得不同Locale对应的ResourceBundle,再从ResourceBundle获取信息,对于MessageSource提供了三种方法:
public interface MessageSource { String getMessage(String code, Object[] args, String defaultMessage, Locale locale); String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException; String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessage zException;}
第二种方法和第一个方法区别在于找不到资源的话会抛出异常
ApplicationContext也实现了MessageSource接口,它会委派MessageSource接口来完成MessageSource的工作,如果不存在这个接口,容器会默认创建一个不含任何内容的StaticMessageSource实例,完成相应的工作
上图是spring实现Message的三个接口
- 容器内部事件发布
自定义事件类型,通过扩展java.util.EventObject类来实现自定义事件类型,实现针对自定义事件类的事件监听接口,对自定义时间进行监听
public interface MethodExecutionEventListener extends EventListener { /** * 处理方法开始执行的时候发布的MethodExecutionEvent事件 */ void onMethodBegin(MethodExecutionEvent evt); /** * 处理方法执行将结束时候发布的MethodExecutionEvent事件 */ void onMethodEnd(MethodExecutionEvent evt);}
自定义事件事项上面的MethodExecutionEventListener接口,针对不同的事件作出相应的处理
以上为准备工作,有了自定义事件和事件监听器,那么就剩下发布事件,事件发布类需要注意的两点是:
public class MethodExeuctionEventPublisher { private List<MethodExecutionEventListener> listeners = new ArrayList<MethodExecutionEventListener>(); public void methodToMonitor() { MethodExecutionEvent event2Publish = new MethodExecutionEvent(this,"methodToMonitor"); publishEvent(MethodExecutionStatus.BEGIN,event2Publish); // 执行实际的方法逻辑 // ... publishEvent(MethodExecutionStatus.END,event2Publish); } protected void publishEvent(MethodExecutionStatus status, MethodExecutionEvent methodExecutionEvent) { List<MethodExecutionEventListener> copyListeners = new ArrayList<MethodExecutionEventListener>(listeners); for(MethodExecutionEventListener listener:copyListeners) { if(MethodExecutionStatus.BEGIN.equals(status)) listener.onMethodBegin(methodExecutionEvent); else listener.onMethodEnd(methodExecutionEvent); } } public void addMethodExecutionEventListener(MethodExecutionEventListener listener) { this.listeners.add(listener); } public void removeListener(MethodExecutionEventListener listener) { if(this.listeners.contains(listener)) this.listeners.remove(listener); } public void removeAllListeners() { this.listeners.clear(); }}
① 具体时点上的事件发布,methodToMonitor()是事件发布的源头,而且对于整个监听事件做了安全复制(safe-copy),防止在事件注册或者删除的时候影响处理过程
② MethodExeuctionEventPublisher提供了事件监听器的添加和移除操作,防止监听器被MethodExeuctionEventPublisher类无限调用,没有remove方法,即使不在使用这些监听器也会依然在MethodExeuctionEventPublisher的监听器列表中,造成内存泄漏
知道了监听事件的工作流程,那么spring的内部事件监听发布的原理已经渐渐浮现:
- ApplicationEvent 自定义监听事件接口,有三个实现类:
- ContextClosedEvent 用于容器即将关闭的时候发布的事件类型
- ContextRefreshedEvent 容器刷新或者初始化时候发布的事件类型
- ContextHandleEvent Web请求处理后发布的事件类型,并且其子类类ServletRequestHandledEvent专门用于JavaEE的Servlet请求事件
- ApplicationListener 自定义事件监听器接口
- ApplicationContext 容器本身就是事件发布者,但是真正的事件发布并非容器本身,而是委派给org.springframework.context.event.ApplicationEventMulticaster接口
由于ApplicationContext容器将监听委托给其他对象,所以一旦启动容器就会查找名称为ApplicationEventMulticaster的对象实例applicationEventMulticaster,如果不存在此对象,就会默认创建一个SimpleApplicationEventMulticaster来完成任务
Spring容器监听事件内部实现结构图
- Spring容器内事件发布的应用
Spring中的ApplicationContext容器内的事件发布机制,主要用于单一容器内的简单消息通知和处理,不适合分布式、多进程、多容器之间的事件通知。
- 多配置模块加载的简化
ApplicationContext容器比BeanFactory做的更加好,并非特有的功能
引入配置文件中BeanFactory就需要创建FileSystemResource的对象进行文件获取,步骤很繁琐,代码量也很大,但是换做是ApplicationContext就比较简单
书中对于这些知识介绍的比较详细,见P.110
- 《Spring揭秘》第五章 读书笔记 —— ApplicationContext
- Spring揭秘(六)——Spring IoC容器ApplicationContext
- 《Spring揭秘》第二章 读书笔记 —— IoC的基本概念
- 《Spring揭秘》第四章 读书笔记 —— Spring的IoC容器之BeanFactory
- 《Spring揭秘》第三章 读书笔记 —— 掌控大局的IoC Service Provider
- 《Spring揭秘》第四章 读书笔记 —— BeanFactory的XML之旅
- 《Spring揭秘》第四章 读书笔记 —— 容器背后的秘密
- Spring实战读书笔记 第五章 征服数据库
- Spring笔记——Spring容器:ApplicationContext
- Spring揭秘 学习笔记三 (Spring的IoC容器 ApplicationContext)
- 《Android框架揭秘》读书笔记——JNI
- Spring IoC——ApplicationContext示例
- spring——BeanFactory和applicationContext
- spring揭秘 读书笔记 一 IoC初探
- Spring揭秘 读书笔记 四----方法注入
- Spring揭秘 读书笔记 五 容器的启动
- spring揭秘 读书笔记 六 bean的一生
- 《推荐系统实践》读书笔记——第五章
- 第十一周项目1-(1)层次遍历算法的验证
- 环境变量配置以mysql为例
- 第十二周项目2-操作用临界表存储的图
- 第12周项目2-操作用邻接表存储的图
- 第12周项目2-操作用邻接表存储的图
- 《Spring揭秘》第五章 读书笔记 —— ApplicationContext
- ViewPager+Fragment
- 洛谷P1558 色板游戏
- Java中创建(实例化)对象的五种方式
- 第十二周 项目一--图基本算法库
- 第十二周项目2-操作用邻接表存储的图
- Android属性动画之ObjectAnimator使用
- 采用SMAC(社交、移动、分析、云计算)规划客户的5种最佳方法
- CMMI3认证过程记录