java配置_SpringMVC详解
⼀、ContextLoaderListener
ContextLoaderListener的作⽤就是启动Web容器时,⾃动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接⼝,l配置这个启动容器时,就会默认执⾏它实现的⽅法。在ContextLoader-Listener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet⽣成。查看ContextLoaderServlet的API,它也关联了ContextLoader这个类⽽且它实现了HttpServlet这个接⼝;ContextLoader创建的是XmlWebApplicationContext这样⼀个类,实现的接⼝是WebApplicationContext-
>ConfigurableWebApplicationContext->ApplicationContext->BeanFactory。这样⼀来spring中的所有bean都由这个类来创建。如果在l中不写任何参数配置信息,默认的路径是/l,在WEB-INF⽬录下创建的xml⽂件的名称必须是l;如果是要⾃定义⽂件名可以在l⾥加⼊contextConfigLocation这个context参数:
contextConfigLocation
/WEB-INF/classes/applicationContext-*.xml
在⾥指定相应的xml⽂件名,如果有多个xml⽂件,可以写在⼀起并⼀“,”号分隔。上⾯的applicationContext-*.xml采⽤通配符,⽐如这那个⽬录下有l,l,l等⽂件,都会⼀同被载⼊。由此可见l的⽂件位置就可以有两种默认实现:第⼀种:直接将之放到/WEB-INF下,之后在
contextConfigLocation
/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml
Spring提供ServletContentListener的⼀个实现类ContextLoaderListener,该类可以作为Listener使⽤,在启动Tomcat容器的时候,该类的作⽤就是⾃动装载ApplicationContext的配置信息,如果没有设置contextConfigLocation的初始参数则会使⽤默认参数WEB-INF路径下的l⽂件。
java xml是什么⼆、IntrospectorCleanupListener
1.Introspector作⽤及影响
在分析IntrospectorCleanupListener之前,先了解⼀下Introspector。Introspector是JDK中java.beans包下的类,它为⽬标JavaBean 提供了⼀种了解原类⽅法、属性和事件的标准⽅法。通俗的说,就是可以通过Introspector构建⼀个BeanInfo对象,⽽这个BeanInfo对象中包含了⽬标类中的属性、⽅法和事件的描述信息,然后可以使⽤这个BeanInfo对象对⽬标对象进⾏相关操作。下⾯看⼀个简单的⽰例会很容易明⽩。为了简单,Student类中只有⼀个name属性。
结果输出:Student{name='张三'}
通过查看BeanInfo⽅法的源码会发现,Introspector在构建⼀个BeanInfo对象的时候,会将构建的BeanInfo对象和原类缓存到⼀个Map中,源码如下。
通过上的代码可以得出,Introspector间接持有了BeanInfo的强引⽤。如果使⽤Introspector操作了很多类,那么Introspector将间接持有这些BeanInfo的强引⽤。在发⽣垃圾收集的时候,检测到这些BeanInfo存在引⽤链,则这些类和对应的类加载器将不会被垃圾收集器回收,进⽽导致内存泄漏。所以,为了解决这个问题,在使⽤Introspector操作完成后,调⽤Introspector类的flushCaches⽅法清除缓存。
通过上⾯的代码会发现,清除的时候是清空了整个缓存,因为没有很好的办法来确定每个缓存是属于哪个应⽤的,所以清除的时候会清除所有应⽤的缓存。
2.IntrospectorCleanupListener解析
上⾯分析了Introspector的作⽤和影响,那IntrospectorCleanupListener和Introspector有什么关系呢?
IntrospectorCleanupListener是spring-web jar中的类,源码如下。
IntrospectorCleanupListener实现了ServletContextListener接⼝,也就是说,在web容器初始化(准确的说是在filters或servlets初始化之前)的时候会执⾏contextInitialized⽅法,在ServletContext销毁(准确的说是在filters和servlets销毁之后)的时候会执⾏contextDestroyed⽅法。从图中contextDestroyed⽅法,可以看到在销毁ServletContext的时候调⽤了Introspector.flushCaches⽅法,清空了对应缓存。IntrospectorCleanupListener中为什么要这么做?难道是Spring使⽤Introspector操作后没有清空对应缓存?查看IntrospectorCleanupListener类的源码,会发现有这样⼀段标注。
⼤意是说,在使⽤Spring本⾝的时候并不需要使⽤此,因为Spring⾃⼰的内部机制会⽴即清空对应的缓存。虽然,Spring本⾝不存在这样的问题,但是如果和其它框架结合使⽤,⽽其它框架有这个问题,如Struts、Quartz等,那就需要配置这个,在销毁ServletContext的时候清空对应缓存。
有⼀点需要注意的是,像这样⼀个简单的Introspector内存泄漏将会导致整个应⽤的类加载器不会被垃圾收集器回收,如果有内存泄漏的问题,可以考虑此因素。
3.配置IntrospectorCleanupListener
此主要⽤于解决java.beans.Introspector导致的内存泄漏的问题。JDK中的java.beans.Introspector类的⽤途是发现Java类是否符合JavaBean规范。如果有的框架或程序⽤到了Introspector类,那么就会启⽤⼀个系统级别的缓存,此缓存会存放⼀些曾加载并分析过的JavaBean的引⽤。当Web服务器关闭时,由于此缓存中存放着这些JavaBean的引⽤,所以垃圾回收器⽆法回收Web容器中的JavaBean对象,最后导致内存变⼤。⽽org.springframework.web.util.IntrospectorCleanupListener就是专门⽤来处理Introspector内存泄漏问题的辅助类。IntrospectorCleanupListener会在Web服务器停⽌时清理Introspector缓存,使那些Javabean能被垃圾回收器正确回收。Spring ⾃⾝不会出现这种问题,因为Spring在加载并分析完⼀个类之后会马上刷新。java.beans.-Introspector缓存,这就保证Spring中不会出现这种内存泄漏的问题。但有些程序和框架在使⽤了JavaBeans Introspector之后,没有进⾏清理⼯作(如Quartz,Struts),最后导致内存泄漏。
在以往的⼯作经历中,多次看到在l中将IntrospectorCleanupListener配置成⾮第⼀个listener。
官⽅的表述是必须将此配置成l中的第⼀个listener,才能在合适的时间发挥最有效的作⽤。原因其实很简单,在Servlet3.0规范之前,的调⽤是随机的,⽽从Servlet3.0开始,的调⽤顺序是根据其在l中配置的顺序,并且实现ServletContextListener的监听
器,contextInitialized⽅法调⽤顺序是按照在l中配置的顺序正序依次执⾏,⽽contextDestroyed⽅法的调⽤顺序是按照在l中配置的顺序逆序依次执⾏。所以,如果Introspector-CleanupListener被配置成了第⼀个listener,那么它的contextDestroyed⽅法将最后⼀个执⾏,将发挥最有效的清除作⽤;⽽如果不是,那么可能会残留未被清除的缓存。
三、RequestContextListener
1.配置⽅式
org.t.request.RequestContextListener
如果你⽤的是早期版本的web容器(Servlet 2.4以前),那么你要使⽤⼀个javax.servlet.Filter的实现。
...
requestContextFilter
org.springframework.web.filter.RequestContextFilter
requestContextFilter
/*
...
两种⽅式完成完全⼀样的功能:基于LocalThread将HTTP request对象绑定到为该请求提供服务的线程上。这使得具有request和session作⽤域的bean能够在后⾯的调⽤链中被访问到。 Request作⽤域  针对每次HTTP请求,Spring容器会根据loginAction bean定义创建⼀个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放⼼的更改所建实例的内部状态,⽽其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作⽤域的bean实例将被销毁。Session作⽤域
针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建⼀个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作⽤域⼀样,你可以根据需要放⼼的更改所创建实例的内部状态,⽽别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Sessio
n最终被废弃的时候,在该HTTP Session作⽤域内的bean也会被废弃掉。 global session作⽤域  global session作⽤域类似于标准的HTTP Session作⽤域,不过它仅仅在基于portlet的web应⽤中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应⽤的各种不同的portlet所共享。在global session作⽤域中定义的bean被限定于全局portlet Session的⽣命周期范围内。 请注意,假如你在编写⼀个标准的基于Servlet的web应⽤,并且定义了⼀个或多个具有global session作⽤域的bean,系统会使⽤标准的HTTP Session作⽤域,并且不会引起任何错误。
2.为什么需要额外的配置RequestContextFilter
也许会有⼀个疑问,已经通过ContextLoaderListener(或ContextLoaderServlet)将Web容器与Spring容器整合,为什么这⾥还要⽤额外的RequestContextListener以⽀持Bean的另外3个作⽤域,原因是ContextLoaderListener实现ServletContextListener接⼝,⽽ServletContextListener只负责监听Web容器的启动和关闭的事件。RequestContextFilter实现ServletRequest-Listener接⼝,该监听HTTP请求事件,Web服务器接收的每次请求都会通知该。通过配置RequestContext-Filter,Spring容器与Web 容器结合的更加密切。
3.作⽤域依赖问题
如果将Web相关作⽤域的Bean注⼊到singleton或prototype的Bean中,这种情况下,需要Spring AOP。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。