电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

springboot如何配置定時(shí)任務(wù)

瀏覽:16日期:2023-04-11 14:29:12

概述

在Java環(huán)境下創(chuàng)建定時(shí)任務(wù)有多種方式:

使用while循環(huán)配合 Thread.sleep(),雖然稍嫌粗陋但也勉強(qiáng)可用 使用 Timer和 TimerTask 使用 ScheduledExecutorService 定時(shí)任務(wù)框架,如Quartz

在SpringBoot下執(zhí)行定時(shí)任務(wù)無(wú)非也就這幾種方式(主要還是后兩種)。只不過(guò)SpringBoot做了許多底層的工作,我們只需要做些簡(jiǎn)單的配置就行了。

通過(guò)注解實(shí)現(xiàn)定時(shí)任務(wù)

在SpringBoot中僅通過(guò)注解就可以實(shí)現(xiàn)常用的定時(shí)任務(wù)。步驟就兩步:

在啟動(dòng)類中添加 @EnableScheduling注解

@EnableScheduling@SpringBootApplicationpublic class MyApplication { public static void main(String[] args) {SpringApplication.run(MyApplication.class, args); } }

在目標(biāo)方法中添加 @Scheduled注解,同時(shí)在 @Scheduled注解中添加觸發(fā)定時(shí)任務(wù)的元數(shù)據(jù)。

@Scheduled(fixedRate = 1000) public void job() {System.out.println(Thread.currentThread().getId() + ' ----- job1 ----- ' + System.currentTimeMillis()); }

注意: 目標(biāo)方法需要沒(méi)有任何參數(shù),并且返回類型為 void 。

這里的定時(shí)任務(wù)元數(shù)據(jù)是“fixRate=1000”,意思是固定間隔每1000毫秒即執(zhí)行一次該任務(wù)。

再來(lái)看幾個(gè) @Schedule注解的參數(shù):

fixedRate:設(shè)置定時(shí)任務(wù)執(zhí)行的時(shí)間間隔,該值為當(dāng)前任務(wù)啟動(dòng)時(shí)間與下次任務(wù)啟動(dòng)時(shí)間之差; fixedDelay:設(shè)置定時(shí)任務(wù)執(zhí)行的時(shí)間間隔,該值為當(dāng)前任務(wù)結(jié)束時(shí)間與下次任務(wù)啟動(dòng)時(shí)間之差; cron:通過(guò)cron表達(dá)式來(lái)設(shè)置定時(shí)任務(wù)啟動(dòng)時(shí)間,在Cron Generator網(wǎng)站可以直接生成cron表達(dá)式。

這樣創(chuàng)建的定時(shí)任務(wù)存在一個(gè)問(wèn)題:如存在多個(gè)定時(shí)任務(wù),這些任務(wù)會(huì)同步執(zhí)行,也就是說(shuō)所有的定時(shí)任務(wù)都是在一個(gè)線程中執(zhí)行。

再添幾個(gè)定時(shí)任務(wù)來(lái)執(zhí)行下看看:

@Scheduled(fixedRate = 1000) public void job1() {System.out.println(Thread.currentThread().getId() + ' ----- job1 ----- ' + System.currentTimeMillis()); } @Scheduled(fixedRate = 1000) public void job2() {System.out.println(Thread.currentThread().getId() + ' ----- job2 ----- ' + System.currentTimeMillis()); } @Scheduled(fixedRate = 1000) public void job3() {System.out.println(Thread.currentThread().getId() + ' ----- job3 ----- ' + System.currentTimeMillis()); }

代碼中一共創(chuàng)建了三個(gè)定時(shí)任務(wù),每個(gè)定時(shí)任務(wù)的執(zhí)行間隔都是1000毫秒,在任務(wù)體中輸出了執(zhí)行任務(wù)的線程ID和執(zhí)行時(shí)間。

看下執(zhí)行結(jié)果:

20 ----- job3 ----- 157312056826320 ----- job1 ----- 157312056826320 ----- job2 ----- 157312056826320 ----- job3 ----- 157312056926420 ----- job1 ----- 157312056926420 ----- job2 ----- 157312056926420 ----- job3 ----- 157312057026320 ----- job1 ----- 157312057026320 ----- job2 ----- 1573120570263

可以看到這三個(gè)定時(shí)任務(wù)的執(zhí)行有如下的特點(diǎn):

所有的定時(shí)任務(wù)每次都是在同一個(gè)線程上執(zhí)行; 雖然未必是job1第一個(gè)開始執(zhí)行,但是每批任務(wù)的執(zhí)行次序是固定的——這是由fixRate參數(shù)決定的

這樣的定時(shí)任務(wù)已經(jīng)能夠覆蓋絕大部分的使用場(chǎng)景了,但是它的缺點(diǎn)也很明顯:前面的任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng)必然會(huì)影響之后的任務(wù)的執(zhí)行。為了解決這個(gè)問(wèn)題,我們需要異步執(zhí)行定時(shí)任務(wù)。接下來(lái)的部分我們將主要著眼于如何實(shí)現(xiàn)異步執(zhí)行定時(shí)任務(wù)。

通過(guò)@Async注解實(shí)現(xiàn)異步定時(shí)任務(wù)

最常用的方式是使用 @Async注解來(lái)實(shí)現(xiàn)異步執(zhí)行定時(shí)任務(wù)。啟用 @Async注解的步驟如下:

在啟動(dòng)類中添加 @EnableAsync注解:

@EnableAsync@EnableScheduling@SpringBootApplicationpublic class MyApplication { public static void main(String[] args) {SpringApplication.run(MyApplication.class, args); } }

在定時(shí)任務(wù)方法上添加 @Async注解

@Async @Scheduled(fixedRate = 1000) public void job1() {System.out.println(Thread.currentThread().getId() + ' ----- job1 ----- ' + System.currentTimeMillis()); }

我們?yōu)榍懊娴娜齻€(gè)定時(shí)任務(wù)都加上 @Async注解再運(yùn)行看看:

25 ----- job1 ----- 157312178141524 ----- job3 ----- 157312178141526 ----- job2 ----- 157312178141530 ----- job3 ----- 157312178229831 ----- job1 ----- 157312178229932 ----- job2 ----- 157312178229925 ----- job2 ----- 157312178330435 ----- job3 ----- 157312178330636 ----- job1 ----- 1573121783306

通過(guò)輸出信息可以看到每個(gè)定時(shí)任務(wù)都在不同的線程上執(zhí)行,彼此的執(zhí)行次序和執(zhí)行時(shí)間也互不影響,說(shuō)明配置為異步執(zhí)行已經(jīng)成功。

通過(guò)配置實(shí)現(xiàn)異步定時(shí)任務(wù)

現(xiàn)在我們有必要稍稍深入了解下springboot定時(shí)任務(wù)的執(zhí)行機(jī)制了。

springboot的定時(shí)任務(wù)主要涉及到兩個(gè)接口: TaskScheduler和 TaskExecutor。在springboot的默認(rèn)定時(shí)任務(wù)實(shí)現(xiàn)中,這兩個(gè)接口的實(shí)現(xiàn)類是 ThreadPoolTaskScheduler和 ThreadPoolTaskExecutor。

ThreadPoolTaskScheduler負(fù)責(zé)實(shí)現(xiàn)任務(wù)的定時(shí)執(zhí)行機(jī)制,而 ThreadPoolTaskExecutor則負(fù)責(zé)實(shí)現(xiàn)任務(wù)的異步執(zhí)行機(jī)制。二者中, ThreadPoolTaskScheduler執(zhí)行棧更偏底層一些。

盡管在職責(zé)上有些區(qū)別,但是兩者在底層上都是依賴java的線程池機(jī)制實(shí)現(xiàn)的: ThreadPoolTaskScheduler依賴的底層線程池是 ScheduledExecutorService,springboot默認(rèn)為其提供的coreSize是1,所以默認(rèn)的定時(shí)任務(wù)都是在一個(gè)線程中執(zhí)行; ThreadPoolTaskExecutor依賴的底層線程池是 ThreadPoolExecutor,springboot默認(rèn)為其提供的corePoolSize是8。

說(shuō)到這里應(yīng)該清楚了:我們可以不添加 @Async注解,僅通過(guò)調(diào)整 ThreadPoolTaskScheduler依賴的線程池的coreSize也能實(shí)現(xiàn)多線程異步執(zhí)行;同樣的,即使添加了 @Async注解,將 ThreadPoolTaskExecutor依賴的線程池的corePoolSize設(shè)置為1,那定時(shí)任務(wù)還是只能在一個(gè)線程上同步執(zhí)行。看下springboot的相關(guān)配置項(xiàng):

spring: task: scheduling: pool:size: 1 execution: pool:core-size: 2

其中spring.task.scheduling是 ThreadPoolTaskScheduler的線程池配置項(xiàng),spring.task.execution是 ThreadPoolExecutor的線程池配置項(xiàng)。

再稍稍擴(kuò)展下: @Async注解的value屬性就是用來(lái)指明使用的 TaskExecutor實(shí)例的。默認(rèn)值是空字符串,表示使用的是springboot自啟動(dòng)的 TaskExecutor實(shí)例。如有需要,也可以使用自定義的 TaskExecutor實(shí)例,如下:

/** * 配置線程池 * @return */ @Bean(name = 'scheduledPoolTaskExecutor') public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(20);taskExecutor.setMaxPoolSize(200);taskExecutor.setQueueCapacity(25);taskExecutor.setKeepAliveSeconds(200);taskExecutor.setThreadNamePrefix('my-task-executor-');// 線程池對(duì)拒絕任務(wù)(無(wú)線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy;默認(rèn)為后者taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//調(diào)度器shutdown被調(diào)用時(shí)等待當(dāng)前被調(diào)度的任務(wù)完成taskExecutor.setWaitForTasksToCompleteOnShutdown(true);//等待時(shí)長(zhǎng)taskExecutor.setAwaitTerminationSeconds(60);taskExecutor.initialize();return taskExecutor; }

此外,還有一種做法是通過(guò)提供自定義的 TaskScheduler Bean實(shí)例來(lái)實(shí)現(xiàn)異步執(zhí)行。要提供提供自定義的 TaskScheduler 實(shí)例,可以直接通過(guò) @Bean注解聲明創(chuàng)建,也可以在 SchedulingConfigurer接口中配置。這些在后面我們會(huì)提到。

調(diào)用SpringBoot接口實(shí)現(xiàn)定時(shí)任務(wù)

有時(shí)候會(huì)需要將定時(shí)任務(wù)的定時(shí)元數(shù)據(jù)寫在數(shù)據(jù)庫(kù)或其他配置中心以便統(tǒng)一維護(hù)。這種情況就不是通過(guò)注解能夠搞定的了,此時(shí)我們需要使用springboot定時(shí)任務(wù)一些組件來(lái)自行編程實(shí)現(xiàn)。常用的組件包括 TaskScheduler、 Triger接口和 SchedulingConfigurer接口。

注意:因?yàn)槲覀冇玫搅藄pringboot的定時(shí)任務(wù)組件,所以仍然需要在啟動(dòng)類上添加 @EnableScheduling注解。

Trigger接口

Trigger接口主要用來(lái)設(shè)置定時(shí)元數(shù)據(jù)。要通過(guò)程序?qū)崿F(xiàn)定時(shí)任務(wù)就不能不用到這個(gè)接口。這個(gè)接口有兩個(gè)實(shí)現(xiàn)類:

PeriodicTrigger用來(lái)配置固定時(shí)長(zhǎng)的定時(shí)元數(shù)據(jù) CronTrigger用來(lái)配置cron表達(dá)式定時(shí)元數(shù)據(jù)

使用TaskScheduler接口

TaskScheduler接口前面我們提過(guò),這個(gè)接口需要配合 Trigger接口一起使用來(lái)實(shí)現(xiàn)定時(shí)任務(wù),看個(gè)例子:

@Autowired private TaskScheduler taskScheduler; public void job() {int fixRate = 10;taskScheduler.schedule(() -> System.out.println(' job4 ----- ' + System.currentTimeMillis()),new PeriodicTrigger(fixRate, TimeUnit.SECONDS)); }

在上面的代碼里,我們使用 @Autowired注解獲取了springbootr容器里默認(rèn)的 TaskScheduler實(shí)例,然后通過(guò) PeriodicTrigger設(shè)置了定時(shí)元數(shù)據(jù),定時(shí)任務(wù)的任務(wù)體則是一個(gè) Runable接口的實(shí)現(xiàn)(在這里只是輸出一行信息)。

因?yàn)槟J(rèn)的 TaskScheduler實(shí)例的線程池coreSize是1,所以如有多個(gè)并發(fā)任務(wù),這些任務(wù)的執(zhí)行仍然是同步的。要調(diào)整為異步可以在配置文件中配置,也可以通過(guò)提供一個(gè)自定義的 TaskScheduler實(shí)例來(lái)設(shè)置:

@Bean('taskScheduler') public TaskScheduler taskExecutor() {ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();executor.setPoolSize(20);executor.setThreadNamePrefix('my-task-scheduler');executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//調(diào)度器shutdown被調(diào)用時(shí)等待當(dāng)前被調(diào)度的任務(wù)完成executor.setWaitForTasksToCompleteOnShutdown(true);//等待時(shí)長(zhǎng)executor.setAwaitTerminationSeconds(60);return executor; }

使用SchedulingConfigurer接口

SchedulingConfigurer接口的主要用處是注冊(cè)基于 Trigger接口自定義實(shí)現(xiàn)的定時(shí)任務(wù)。

在實(shí)現(xiàn) SchedulingConfigurer接口后,通常還需要使用 @Configuration注解(當(dāng)然啟動(dòng)類上的 @EnableScheduling注解也不能少)來(lái)聲明它實(shí)現(xiàn)類。

這個(gè)接口唯一的一個(gè)方法就是configureTasks,字面意思是配置定時(shí)任務(wù)。這個(gè)方法最重要的參數(shù)是一個(gè) ScheduledTaskRegistrar定時(shí)任務(wù)注冊(cè)類實(shí)例,該類有8個(gè)方法,允許我們以不同的方式注冊(cè)定時(shí)任務(wù)。

簡(jiǎn)單做了個(gè)實(shí)現(xiàn):

@Configurationpublic class MyTaskConfigurer implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.addCronTask(() -> System.out.println(Thread.currentThread().getId() + ' --- job5 ----- ' + System.currentTimeMillis()),'0/1 * * * * ?'); taskRegistrar.addFixedDelayTask(() -> System.out.println(Thread.currentThread().getId() + ' --- job6 ----- ' + System.currentTimeMillis()),1000); taskRegistrar.addFixedRateTask(() -> System.out.println(Thread.currentThread().getId() + ' --- job7 ----- ' + System.currentTimeMillis()),1000); }}

這里我們只使用了三種注冊(cè)任務(wù)的方法,分別嘗試注冊(cè)了fixDelay、fixRate以及cron觸發(fā)的定時(shí)任務(wù)。

springboot會(huì)自動(dòng)啟動(dòng)注冊(cè)的定時(shí)任務(wù)。看下執(zhí)行結(jié)果:

22 --- job7 ----- 157361361634922 --- job6 ----- 157361361635022 --- job5 ----- 157361361700122 --- job7 ----- 157361361735222 --- job6 ----- 157361361735322 --- job5 ----- 157361361806522 --- job7 ----- 157361361835022 --- job6 ----- 157361361835522 --- job5 ----- 1573613619002

在執(zhí)行結(jié)果中可以看到這里的任務(wù)也是在單一線程同步執(zhí)行的。要設(shè)置為異步執(zhí)行也簡(jiǎn)單,因?yàn)?SchedulingConfigurer接口的另一個(gè)作用就是為定時(shí)任務(wù)提供自定義的 TaskScheduler實(shí)例。來(lái)看下:

@Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setThreadNamePrefix('my-task-scheduler');scheduler.setPoolSize(10);scheduler.initialize();taskRegistrar.setTaskScheduler(scheduler); }

在這里,我將之前注冊(cè)的定時(shí)任務(wù)去掉了,目的是想驗(yàn)證下這里的配置是否對(duì)注解實(shí)現(xiàn)的定時(shí)任務(wù)有效。經(jīng)檢驗(yàn)是可行的。當(dāng)然對(duì)在configureTasks方法中配置的定時(shí)任務(wù)肯定也是有效的。我就不一一貼結(jié)果了。

另外,需要注意:如 SchedulingConfigurer接口實(shí)例已經(jīng)注入,將無(wú)法再獲取到springboot默認(rèn)提供的 TaskScheduler接口實(shí)例。

通過(guò)Quartz實(shí)現(xiàn)定時(shí)任務(wù)

Quartz是一個(gè)非常強(qiáng)大的定時(shí)任務(wù)管理框架。短短的一篇文章未必能介紹清楚Quartz的全部用法。所以這里只是簡(jiǎn)單地演示下如何在springboot中是如何使用Quartz的。更多的用法建議優(yōu)先參考Quartz官方文檔。

在spring-boot-web 2.0及之后的版本,已經(jīng)自動(dòng)集成了quartz,如果不使用spring-boot-web或使用較早的版本的話我們還需要加一些依賴:

<!-- quartz --> <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId> </dependency> <!-- spring集成quartz --> <dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId> </dependency> <!-- SchedulerFactoryBean依賴了tx包中的PlatformTransactionManager類,因?yàn)閝uartz的分布式功能是基于數(shù)據(jù)庫(kù)完成的 --> <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId> </dependency>

添加完成這些依賴后,springboot服務(wù)在啟動(dòng)時(shí)也會(huì)自啟動(dòng)內(nèi)部的quartz。事實(shí)上springboot已經(jīng)為我們準(zhǔn)備好了幾乎全部的quartz的配置。我們要做的只是把自定義的任務(wù)填進(jìn)去。

首先我們需要?jiǎng)?chuàng)建一個(gè)Job實(shí)例,來(lái)實(shí)現(xiàn)Job的具體行為。

@Componentpublic class MyQuartzJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) {JobDataMap map = context.getMergedJobDataMap();// 從作業(yè)上下文中取出KeyString key = map.getString('key');System.out.println(Thread.currentThread().getId() + ' -- job8 ---------------------->>>>' + key); } }

QuartzJobBean是Spring提供的Quartz Job抽象類。在實(shí)現(xiàn)這個(gè)類的時(shí)候我們可以獲取注入到spring中的其他Bean。

配置Job

@Configurationpublic class QuartzConfig implements InitializingBean { @Autowired private SchedulerFactoryBean schedulerFactoryBean; @Override public void afterPropertiesSet() throws Exception {config(); } private void config() throws SchedulerException {Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobDetail jobDetail = buildJobDetail();Trigger trigger = buildJobTrigger(jobDetail);scheduler.scheduleJob(jobDetail, trigger); } private JobDetail buildJobDetail() {// 用來(lái)存儲(chǔ)交互信息JobDataMap dataMap = new JobDataMap();dataMap.put('key', 'zhyea.com'); return JobBuilder.newJob(MyQuartzJob.class).withIdentity(UUID.randomUUID().toString(), 'chobit-job').usingJobData(dataMap).build(); } private Trigger buildJobTrigger(JobDetail jobDetail) {return TriggerBuilder.newTrigger().forJob(jobDetail).withIdentity(jobDetail.getKey().getName(), 'chobit-trigger').withSchedule(CronScheduleBuilder.cronSchedule('0/1 * * * * ?')).build(); }}

在創(chuàng)建 QuartzConfig類的時(shí)候?qū)崿F(xiàn)了 InitializingBean接口,目的是在 QuartzConfig實(shí)例及依賴類都完成注入后可以立即執(zhí)行配置組裝操作。

這里面有幾個(gè)關(guān)鍵接口需要說(shuō)明下:

SchedulerFactoryBean,Quartz Scheduler工廠類,springboot自動(dòng)化配置實(shí)現(xiàn); Scheduer,負(fù)責(zé)Quartz Job調(diào)度,可從工廠類實(shí)例獲取; JobDetail,執(zhí)行Quartz Job封裝; Trigger,完成Quartz Job啟動(dòng)。

還可以在配置文件中添加Quartz的配置:

spring: quartz: startupDelay: 180000 #這里是毫秒值

這里配置了讓Quartz默認(rèn)延遲啟動(dòng)3分鐘。

看下執(zhí)行結(jié)果:

30 -- job8 ---------------------->>>>zhyea.com31 -- job8 ---------------------->>>>zhyea.com32 -- job8 ---------------------->>>>zhyea.com33 -- job8 ---------------------->>>>zhyea.com34 -- job8 ---------------------->>>>zhyea.com...

好了,就這些內(nèi)容了。前面用到的程序都上傳到了GITHUB,有需要可以參考下。

參考文檔

Spring Task Execution and SchedulingScheduling TasksSpringBoot Quartz SchedulerSpring Boot Quartz Scheduler Example: Building an Email Scheduling appQuartz Scheduler Tutorials

以上就是springboot如何配置定時(shí)任務(wù)的詳細(xì)內(nèi)容,更多關(guān)于springboot配置定時(shí)任務(wù)的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 压缩空气冷冻式干燥机_吸附式干燥机_吸干机_沪盛冷干机 | 成都顶呱呱信息技术有限公司-贷款_个人贷款_银行贷款在线申请 - 成都贷款公司 | 黄石东方妇产医院_黄石妇科医院哪家好_黄石无痛人流医院 | 上海logo设计| 挤出机_橡胶挤出机_塑料挤出机_胶片冷却机-河北伟源橡塑设备有限公司 | 酶联免疫分析仪-多管旋涡混合仪|混合器-莱普特科学仪器(北京)有限公司 | WF2户外三防照明配电箱-BXD8050防爆防腐配电箱-浙江沃川防爆电气有限公司 | 盘煤仪,盘料仪,盘点仪,堆料测量仪,便携式激光盘煤仪-中科航宇(北京)自动化工程技术有限公司 | 诚暄电子公司首页-线路板打样,pcb线路板打样加工制作厂家 | 搪玻璃冷凝器_厂家-越宏化工设备 | 齿轮减速机_齿轮减速电机-VEMT蜗轮蜗杆减速机马达生产厂家瓦玛特传动瑞环机电 | 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 电磁辐射仪-电磁辐射检测仪-pm2.5检测仪-多功能射线检测仪-上海何亦仪器仪表有限公司 | 继电器模组-IO端子台-plc连接线-省配线模组厂家-世麦德 | 翻斗式矿车|固定式矿车|曲轨侧卸式矿车|梭式矿车|矿车配件-山东卓力矿车生产厂家 | 车间除尘设备,VOCs废气处理,工业涂装流水线,伸缩式喷漆房,自动喷砂房,沸石转轮浓缩吸附,机器人喷粉线-山东创杰智慧 | 不锈钢电动球阀_气动高压闸阀_旋塞疏水调节阀_全立阀门-来自温州工业阀门巨头企业 | 盘扣式脚手架-附着式升降脚手架-移动脚手架,专ye承包服务商 - 苏州安踏脚手架工程有限公司 | 东莞螺丝|东莞螺丝厂|东莞不锈钢螺丝|东莞组合螺丝|东莞精密螺丝厂家-东莞利浩五金专业紧固件厂家 | 篷房|仓储篷房|铝合金篷房|体育篷房|篷房厂家-华烨建筑科技官网 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 呼末二氧化碳|ETCO2模块采样管_气体干燥管_气体过滤器-湖南纳雄医疗器械有限公司 | 浙江华锤电器有限公司_地磅称重设备_防作弊地磅_浙江地磅售后维修_无人值守扫码过磅系统_浙江源头地磅厂家_浙江工厂直营地磅 | 流量检测仪-气密性检测装置-密封性试验仪-东莞市奥图自动化科技有限公司 | Magnescale探规,Magnescale磁栅尺,Magnescale传感器,Magnescale测厚仪,Mitutoyo光栅尺,笔式位移传感器-苏州连达精密量仪有限公司 | 安平县鑫川金属丝网制品有限公司,防风抑尘网,单峰防风抑尘,不锈钢防风抑尘网,铝板防风抑尘网,镀铝锌防风抑尘网 | 2-羟基泽兰内酯-乙酰蒲公英萜醇-甘草查尔酮A-上海纯优生物科技有限公司 | 包头市鑫枫装饰有限公司| 减速机三参数组合探头|TSM803|壁挂式氧化锆分析仪探头-安徽鹏宸电气有限公司 | 节流截止放空阀-不锈钢阀门-气动|电动截止阀-鸿华阀门有限公司 | 洛阳永磁工业大吊扇研发生产-工厂通风降温解决方案提供商-中实洛阳环境科技有限公司 | 品牌广告服务平台,好排名,好流量,好生意。 | 深圳宣传片制作-企业宣传视频制作-产品视频拍摄-产品动画制作-短视频拍摄制作公司 | 九爱图纸|机械CAD图纸下载交流中心| 深圳网站建设-高端企业网站开发-定制网页设计制作公司 | 艺术漆十大品牌_艺术涂料加盟代理_蒙太奇艺术涂料厂家品牌|艺术漆|微水泥|硅藻泥|乳胶漆 | 烟台条码打印机_烟台条码扫描器_烟台碳带_烟台数据采集终端_烟台斑马打印机-金鹏电子-金鹏电子 | pbt头梳丝_牙刷丝_尼龙毛刷丝_PP塑料纤维合成毛丝定制厂_广州明旺 | 编织人生 - 权威手工编织网站,编织爱好者学习毛衣编织的门户网站,织毛衣就上编织人生网-编织人生 | 河南彩印编织袋,郑州饲料编织袋定制,肥料编织袋加工厂-盛军塑业 河南凯邦机械制造有限公司 | 恒温振荡混匀器-微孔板振荡器厂家-多管涡旋混匀器厂家-合肥艾本森(www.17world.net) | 四川成人高考_四川成考报名网 |