2. Spring容器
Spring有两个核心接口:BeanFactory和ApplicationContext,ApplicationContext是BeanFactory的子接口。它们都可代表Spring容器,Spring是生成Bean实例的工厂,并管理容器中的Bean。
2.1 Spring容器
Spring容器最基本的接口是BeanFactory,BeanFactory负责配置、创建、管理Bean,同时负责管理Bean与Bean之间的依赖关系。
BeanFactory接口包含如下几个基本方法:
- boolean containsBean(String name):判断Spring容器是否包含id为name的Bean实例。
- <T> T getBean(Class<T> requiredType):获取Spring容器中属于requiredType类型的,唯一的Bean实例。
- Object getBean(String name):返回容器id为name的Bean实例。
- <T> T getBean(String name, Class<T> requiredType):返回容器中id为name,并且类型为requiredType的Bean。
- Class<?> getType(name):返回容器中id为name的Bean实例的类型。
2.2 ApplicationContext
ApplicationContext是BeanFactory的子接口,通常也称为Spring上下文。其常用实现类是FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext。如果在Web容器中使用Spring容器,则通常有XmlWebApplicationContext、AnnotationConfigWebApplicationContext两个实现类。
除了提供BeanFactory所支持的全部功能外,ApplicationContext还有如下额外的功能:
- ApplicationContext默认会预初始化所有的Singleton Bean(BeanFactory不会),也可通过 配置元素的lazy-init属性 取消预初始化;
- ApplicationContext继承MessageSource接口,因此提供国际化支持;
- 资源访问支持;
- 事件机制;
- 同时加载多个配置文件;
- 以声明式方式启动并创建Spring容器。
ApplicationContext包括BeanFactory的全部功能,因此建议优先使用ApplicationContext。除非对于某些内存非常关键的应用,才考虑使用BeanFactory。
2.3 ApplicationContext的国际化支持
ApplicationContext接口继承了MessageSource接口,因此具有国际化功能。MessageSource接口定义了如下两个方法用于实现国际化:
- String getMessage(String code, Object args[], Locale loc)
- String getMessage(String code, Object args[], String default, Locale loc)
ApplicationContext通过如上两个方法来完成国际化。当程序创建ApplicationContext容器时,Spring自动查找配置文件中名为messageSource的Bean实例,一旦找到这个Bean实例,上述两个方法的调用就被委托给该messageSource Bean(Spring容器并不是实际的调用者)。如果没有该Bean,ApplicationContext或查找其父容器中的messageSource Bean,如果找到,它将被作为messageSource Bean使用。如果无法找到messageSource Bean,系统会创建一个空的StaticMessageSource Bean,该Bean能接受上述两个方法的调用。
在Spring中配置messageSource Bean时通常使用ResourceBundleMessageSource类。
2.4 ApplicationContext的事件机制
ApplicationContext的事件机制是观察者模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext的事件处理。
- ApplicationEvent类:容器事件,必须由ApplicationContext发布(publishEvent()方法)。
- ApplicationListener<T>接口:监听器,可由容器中的任何监听器Bean担任,用于监听T类型的事件;也可以不使用泛型,监听容器中的所有事件。
Spring有如下几个内置事件:
- ContextRefreshEvent:ApplicationContext容器初始化或者刷新,触发该事件。此处的初始化是指,所有的Bean被成功加载,后处理的Bean被检测并激活,所有的Singleton Bean被预实例化,ApplicationContext容器已就绪可用。
- ContextStartedContext:当使用ConfigurableApplicationContext接口的start()方法启动ApplicationContext容器时触发该事件。
- ContextClosedContext:当使用ConfigurableApplicationContext接口的close()方法关闭ApplicationContext容器时触发该事件。
- ContextStopedContext:当使用ConfigurableApplicationContext接口的stop()方法使ApplicationContext容器停止时触发该事件。被停止的Spring容器可以调用start()方法重新启动。
- RequestHandleEvent:Web相关的事件,只能应用与使用DispatcherServlet的Web应用中。在使用Spring作为前端MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。
Spring 4.0.3新增了SessionConnectedEvent、SessionConnectEvent、SessionDisconnectEvent三个事件,用于为Spring新增的WebSocket功能服务。
2.5 让Bean获取Spring容器
在Web应用中,Spring容器通常采用声明式方式配置产生:开发者只要在web.xml文件中配置一个Listener,该Listener将会负责初始化Spring容器,前端MVC框架可以直接调用Spring容器中的Bean,无须访问Spring容器本身。在这种情况下,容器中的Bean处于容器管理下,无需主动访问容器,只需接受容器的依赖注入即可。但这种方式下,程序Bean无法获取他所在的容器。
为了让Bean获取他所在的容器,可以让该Bean实现BeanFactoryAware接口,并实现如下方法:
- setBeanFactory(BeanFactory):该方法有一个参数beanFactory,该参数指向创建它的BeanFactory。
或者实现ApplicationContextAware接口,并实现setApplicationContext(ApplicationContext applicationContext)方法。Spring容器会检测容器中所有的Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContext()方法,调用该方法时,会将容器本身作为参数传给该方法。