您的位置:首页 > 编程语言 > Java开发

spring在web容器启动时执行初始化方法(四种方式)

2017-12-14 16:17 525 查看
需求:在tomcat启动时开启一个定时任务,或初始化slor索引

想法:容器启动时执行方法,最容易想到的就是servlet中可以配置load-on-startup,设置一个正整数也就可以随容器一起启动。

问题:上面的方法很好,但是由于定时任务需要去操作数据库,而项目采用了spring的依赖注入来管理对象,而servlet并不受Spring的管理。若此时在servlet中注入Spring管理的对象,则会报错:javax.naming.NameNotFoundException: Name com.test.InitServlet is not bound in this Context。

所以想要再servlet中操作数据库,只能手动去创建一个service,这显然违背了我们使用Spring的初衷,让项目看起来不伦不类的。那么如何才能在启动WEB容器的时候执行一段初始化代码,并且可以让其被Spring管理呢?

解决方案:

1)InitializingBean 初始化bean类里的具体方法

Spring提供了当一个Bean初始化后执行方法的扩展点:InitializingBean。这里的初始化指的就是当该Bean的属性被注入完成后(注意:这里并不是所有属性都需要被设置),所以InitializingBean接口提供的方法名称也很形象:afterPropertiesSet()。

使用的时,将该Bean注入到Spring容器,之后我们便可以获得Spring容器中的对象了,也就是说,可以得到service方法来执行我们的定时任务了。

具体代码如下:

[java] view
plain copy

@Component  

public class InitServlet implements InitializingBean {  

  

    /** 

     *  

     */  

    private static final long serialVersionUID = 1L;  

      

    @Resource  

    private DispatchesService dispatchesService;  

  

    @Override  

    public void afterPropertiesSet() throws Exception {  

    <span style="white-space:pre">    </span>dispatchesService.spyDDetails();  

    }  

  

}  

2)spring XML文件直接配置

若采用XML来配置Bean的话,可以指定属性init-method

<bean id="testInitializingBean" class="com.TestInitializingBean" init-method="testInit"></bean>


3)通过注解@PostConstruct来修改初始化方法

值得注意的是,三者可以同时存在,触发的顺序是先触发@PostConstruct修饰的方法,再触发afterPropertiesSet(),最后触发init-method

其中@PostConstruct是通过注册一个BeanPostProcessor,在Bean的初始化方法之前调用,而afterPropertiesSet()和init-method都在初始化方法中调用

关于@PostConstruct详细的介绍可以看这里:http://blog.csdn.net/yaerfeng/article/details/8447530

下面是Spring中调用Bean的初始化代码的源代码:

[java] view
plain copy

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)  

            throws Throwable {  

  

        boolean isInitializingBean = (bean instanceof InitializingBean);  

        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {  

            if (logger.isDebugEnabled()) {  

                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");  

            }  

            if (System.getSecurityManager() != null) {  

                try {  

                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  

                        public Object run() throws Exception {  

                            ((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">// 这里触发afterPropertiesSet</span><span style="white-space:pre">  

</span>  

                            return null;  

                        }  

                    }, getAccessControlContext());  

                }  

                catch (PrivilegedActionException pae) {  

                    throw pae.getException();  

                }  

            }                 

            else {  

                ((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span>// 这里触发afterPropertiesSet  

            }  

        }  

  

        if (mbd != null) {  

            String initMethodName = mbd.getInitMethodName();// 这里是触发init-method  

            if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&  

                    !mbd.isExternallyManagedInitMethod(initMethodName)) {  

                invokeCustomInitMethod(beanName, bean, mbd);  

            }  

        }  

    }  

4)Bean都初始化完成后,实现ApplicationListener<ContextRefreshedEvent>接口

还有一种方法,是当Spring将所有的Bean都初始化完成后,会留给我们一个入口,我们可以实现如下接口

[java] view
plain copy

@Component  

public class InstantiationTracingBeanPostProcessor implements  

        ApplicationListener<ContextRefreshedEvent> {  

  

    @Override  

    public void onApplicationEvent(ContextRefreshedEvent arg0) {  

        System.out.println("-----所有Bean载入完成---");  

    }  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: