背景
最近在做两个表之间的增量数据的同步,利用公司已有的工具,实现源表和目标表之间的增量数据同步的功能。工具内部利用了数据库的binlog机制,同时借助zookeeper和kafka来完成增量数据的读取和发送。
而我需要做的就是监听源表中数据的变化比如新增记录,然后将消息解析成我需要的数据,插入到目标表中。这里就不介绍功能的实现细节了,主要分享下其中的一个点。
鉴于现有框架的代码,我必须要在项目中启动一个线程完成监听。显然,我可以通过写一个main方法主动调用这个服务用于启动线程进行监听。但是在项目容器启动的时候,我没有办法通过手动执行main方法的方式来满足我的需求。那么有没有方法可以实现自启动一个线程呢,在一个容器中又是如何做到这样的效果呢,这就是今天要说的在Spring中如何自启动一个类。
实现思路
首先,我们看下通过主动调用是如何实现的,我们需要一个main函数以及一个业务实现类
加载Spring的配置文件application-context.xml
得到相应的bean实例
注册业务实现类
开启监听线程进行监听
下面就说说如何实现自启动。在Spring要实现自启动,我们有两种方式:实现InitializingBean接口和声明init-method方法
实现InitializingBean接口
从该接口的命名我们就基本知道他的作用,其主要为Spring提供了初始化一个bean途径。InitializingBean接口只有一个方法afterPropertiesSet()
afterPropertiesSet是会在所有的属性设置完(即setXX)后才会被执行到,比如你内部会注入另外一个对象,那么该方法会等到依赖的对象注入后才会执行,这样也确保有依赖bean的场景能够正常工作。
针对我们的业务场景,可以创建一个这样的TestListener类
TestListener实现了接口InitializingBean,并复写了afterPropertiesSet方法
在TestListener上添加了注解@Component,表示其受Spring监管,这样写就不需要在XML文件配置一行<bean>标签了(注意该类要在component-scan能够扫描的路径下,否则Spring是无权监管的)
这样,启动Spring容器的时候,我们通过打断点的方式就可以看到进入了afterPropertiesSet方法
声明init-method方法
上面的方式显然是能够满足我们的要求的,但是他也有不足,就是与Spring的耦合度过高。我们必须在自己的类上实现这个InitializingBean接口,而且要通过复写afterPropertiesSet方法,在该方法中实现我们想要的逻辑,这看起来像个牢笼,对我们约束的太多。
其实我们有一个更加灵活的方法,那就是利用<bean>标签的init-method属性。好比这样
<bean id="testListener" class="com.jackie.TestListener" init-method="init"></bean>
这时候,我们不需要@Component,也不需要实现InitializingBean,只需要在TestListener中添加一个init方法,然后将你的业务逻辑放进去就行。
这样,我们在启动Spring容器时,会扫描到bean名称为testListener的bean,然后进入他的初识化方法init。
InitializingBean和init-method的关系
两者是可以共存并且是有先后执行关系的,以Spring的视角来看,这两个都是属于bean的范畴,Spring会判定是否是InitializingBean,进而执行afterPropertiesSet方法,然后再执行init-method方法,具体实现在抽象类AbstractAutowireCapableBeanFactory中