如何在filter中使用bean实例,web服务启动配置加载顺序

接上一篇末尾讨论到,解决问题是在filter里面注入bean,这个方法有多种,下面简单探讨一下.

先介绍下web服务加载顺序和bean的初始化步骤,具体如下:

 

web服务器加载配置顺序: 


web.xml加载过程(步骤): 


1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点:

2.容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文.

3.容器将转化为键值对,并交给ServletContext.

4.容器创建中的类实例,即创建监听.

5.在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得:

ServletContext = ServletContextEvent.getServletContext(); 
context-param的值 = ServletContext.getInitParameter(“context-param的键”);

6.得到这个context-param的值之后,你就可以做一些操作了.注意,这个时候你的WEB项目还没有完全启动完成.这个动作会比 所 有的Servlet都要早. 
换句话说,这个时候,你对中的键值做的操作,将在你的WEB项目完全启动之前被执行.

7.这个监听是自己写的一个类,除了初始化方法,它还有销毁方法.用于关闭应用前释放资源.比如说数据库连接的关闭.

web.xml节点加载顺序:

        节点的加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。最终得出的web服务启动加载结论是:context-param -> listener -> filter -> servlet -> spring.

 

Bean的初始化顺序应该是: 


1.构造函数。 
2.初始化属性。 
3.如果实现了BeanFactoryAware 接口执行setBeanFactory方法。 
4..如果实现了InitializingBean 接口执行afterPropertiesSet方法。 
5.如果在配置文件中指定了init-method,那么执行该方法。 
6..如果实现了BeanFactoryPostProcessor 接口在 “new”其他类之前执行 postProcessBeanFactory 方法(通过这个方法可以改变配置文件里面的属性值的配置)。 
7.如果实现了BeanFactoryPostProcessor 接口,那么会在其他bean初始化方法之前执行postProcessBeforeInitialization 方法,之后执行postProcessAfterInitialization方法。

    注意:  对于filter配置而言,与它们出现的顺序是有关的。web.xml 中当然可以定义多个 filter,web 容器启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。与 filter 相关的一个配置节是 filter-mapping,他个filter相对应,特别要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。

 

        回到我们的问题,需要在filter中注入bean,    因为加载顺序是: 先加载filter, 后加载spring. 所以在filter中直接用@Autowired和 @Resource注入获取的实例是空的,都会出现NullPointerException.

        解决办法就只能提前初始化需要注入的bean, 可以提前到listener或者filter中就可以了.

        

    第一种:在filter中初始化

       在filter中初始化,即在init中对bean进行初始化.当然也需要在spring配置这个bean的

  初始化,在filter的init初始化方式如下:

 ApplicationContext ct=new FileSystemXmlApplicationContext("classpath*:applicationContext.xml");
 dataStatisticService = (DataStatisticService)ct.getBean("dataStatistMonitor");

        有兴趣的话,可以看看上一篇的问题解决过程.        

    第二种:在listener中初始化

        (1)Listener的生命周期是由servlet容器(例如tomcat)管理的,项目启动时上例中的ConfigListener是由servlet容器实例化并调用其contextInitialized方法,而servlet容器并不认得@Autowired注解,因此导致ConfigService实例注入失败。

        (2)而spring容器中的bean的生命周期是由spring容器管理的。

        那么该如何在spring容器外面获取到spring容器bean实例的引用呢?这就需要用到spring为我们提供的WebApplicationContextUtils工具类,该工具类的作用是获取到spring容器的引用,进而获取到我们需要的bean实例.

        具体如下:  

        1.建一个监听类,重写 ServletContextListener的 contextInitialized和contextDestroyed 方法

        

public class MyListener implements ServletContextListener {
     
    @Override
    public void contextInitialized(ServletContextEvent sce) {   
       	ServletContext servletContext = filterConfig.getServletContext();
	WebApplicationContext webAC = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
	dataStatistic = webAC.getBean(DataStatistic.class);
    }
 
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
 
}

        2.在web.xml配置 ,启动的时候就会加载到这个listener.

        这样就可以在spring之前可以获取到这个bean的实例进行使用了.

    其实这种方法,在前面加载后台线程的那篇已经提到了,有兴趣的可以去看看   .

        

转载于:https://my.oschina.net/mindfind/blog/893978

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值