springboot-quartz普通任务与可传参任务
两者区别与作用:
普通任务:总调度(SchedulerFactoryBean)--> 定时调度器(CronTriggerFactoryBean) --> 调度明细自定义执行方法bean(MethodInvokingJobDetailFactoryBean) -->调度bean(我们定义的job类)
可传参任务:总调度(SchedulerFactoryBean)--> 定时调度器(CronTriggerFactoryBean) --> 调度明细bean(JobDetailFactoryBean)
如上是我们在配置调度器时的具体步骤及相互之间的依赖,区别主要在调度明细bean上,普通任务是(MethodInvokingJobDetailFactoryBean),而可传参任务是(JobDetailFactoryBean):
1)普通任务可以自定义执行方法,也就是说在其配置的调度bean(我们定义的job类)中我们可以自定义调度器最终执行的方法,可以叫work1也可以叫work2,and so on。而且要记住的一点,必须是无入参的方法!!!(做了一个测试,测试目的是看通过此类型调度类型是否也能传入参数所以定义了一个带入参的自定义方法即public void work(JobExecutionContext jobExecutionContext),最中测试结果是spring quartz会报找不到work方法及No such method work(),其默认执行我们生命的work无入参的方法。
2)可传参任务必须继承QuartzJobBean,重写protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException方法,其中JobExecutionContext就是我们在定义调度器明细时传入参数的上下文,我们可以通过JobExecutionContext取出传入的map,调度任务最终执行的就是executeInternal方法,使用该调度明细任务无法使用自定义方法。
提供三种形式的定时任务:
1、固定等待时间 @Scheduled(fixedDelay = 时间间隔 )
2、固定间隔时间 @Scheduled(fixedRate = 时间间隔 )
3、Corn表达式 @Scheduled(cron = Corn表达式)
添加依赖(不知道为什么要加jboss-logging依赖,没有会报错)
- <!-- 添加springboot对Quartz的支持 -->
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz</artifactId>
- <version>2.3.0</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
- <dependency>
- <groupId>org.jboss.logging</groupId>
- <artifactId>jboss-logging</artifactId>
- </dependency>
配置quartz.properties
- #===============================================================
- #Configure Main Scheduler Properties 调度器属性
- #===============================================================
- #调度器的实例名
- org.quartz.scheduler.instanceName = QuartzScheduler
- #调度器的实例ID,大多数情况设置为auto即可
- org.quartz.scheduler.instanceId = AUTO
- #===============================================================
- #Configure ThreadPool 线程池属性
- #===============================================================
- #处理Job的线程个数,至少为1,但最多的话最好不要超过100,在多数机器上设置该值超过100的话就会显得相当不实用了,特别是在你的 Job 执行时间较长的情况下
- org.quartz.threadPool.threadCount = 5
- #线程的优先级,优先级别高的线程比级别低的线程优先得到执行。最小为1,最大为10,默认为5
- org.quartz.threadPool.threadPriority = 5
- #一个实现了 org.quartz.spi.ThreadPool 接口的类,Quartz 自带的线程池实现类是 org.quartz.smpl.SimpleThreadPool
- org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
- #===============================================================
- #Configure JobStore 作业存储设置
- #===============================================================
- #要使 Job 存储在内存中需通过设置 org.quartz.jobStrore.class 属性为 org.quartz.simpl.RAMJobStore
- org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
一、普通任务
1、任务类
- package cloud.app.prod.home.quartz.mem;
- import org.apache.log4j.Logger;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.stereotype.Component;
- import cloud.app.prod.home.common.FailException;
- /**
- * Author : YongBo Xie </br>
- * File Name: ScheduleTask.java </br>
- * Created Date: 2018年3月31日 下午3:37:43 </br>
- * Modified Date: 2018年3月31日 下午3:37:43 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- @Component // 此注解必加
- @EnableScheduling // 此注解必加
- public class ScheduleTask {
- private static Logger logger = Logger.getLogger(ScheduleTask.class);
- public void marketingActivity() throws FailException {
- logger.info("execute activity");
- }
- }
2、Quartz配置类
- package cloud.app.prod.home.quartz.mem;
- import org.quartz.Trigger;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
- import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
- import org.springframework.scheduling.quartz.SchedulerFactoryBean;
- /**
- * Author : YongBo Xie </br>
- * File Name: QuartzConfigration.java </br>
- * Created Date: 2018年3月31日 下午3:42:04 </br>
- * Modified Date: 2018年3月31日 下午3:42:04 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- public class QuartzConfigration {
- /**
- * Details:配置定时任务
- */
- @Bean(name = "marketingActivityJobDetail")
- public MethodInvokingJobDetailFactoryBean detailFactoryBean(ScheduleTask task) {// ScheduleTask为需要执行的任务
- MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
- /*
- * 是否并发执行
- * 例如每5s执行一次任务,但是当前任务还没有执行完,就已经过了5s了,
- * 如果此处为true,则下一个任务会执行,如果此处为false,则下一个任务会等待上一个任务执行完后,再开始执行
- */
- jobDetail.setConcurrent(false);
- jobDetail.setName("marketing_activity");// 设置任务的名字
- jobDetail.setGroup("marketing_activity");// 设置任务的分组,这些属性都可以存储在数据库中,在多任务的时候使用
- /*
- * 为需要执行的实体类对应的对象
- */
- jobDetail.setTargetObject(task);
- /*
- * marketingActivity为需要执行的方法
- * 通过这几个配置,告诉JobDetailFactoryBean我们需要执行定时执行ScheduleTask类中的marketingActivity方法
- */
- jobDetail.setTargetMethod("marketingActivity");
- return jobDetail;
- }
- /**
- * Details:配置定时任务的触发器,也就是什么时候触发执行定时任务
- */
- @Bean(name = "marketingActivityJobTrigger")
- public CronTriggerFactoryBean cronJobTrigger(MethodInvokingJobDetailFactoryBean jobDetail) {
- CronTriggerFactoryBean tigger = new CronTriggerFactoryBean();
- tigger.setJobDetail(jobDetail.getObject());
- tigger.setCronExpression("0 0 1 * * ?");// 初始时的cron表达式 ,每天1点执行
- tigger.setName("marketing_activity");// trigger的name
- return tigger;
- }
- /**
- * Details:定义quartz调度工厂
- */
- @Bean(name = "marketingActivityScheduler")
- public SchedulerFactoryBean schedulerFactory(Trigger cronJobTrigger) {
- SchedulerFactoryBean bean = new SchedulerFactoryBean();
- // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
- bean.setOverwriteExistingJobs(true);
- // 延时启动,应用启动1秒后
- bean.setStartupDelay(1);
- // 注册触发器
- bean.setTriggers(cronJobTrigger);
- return bean;
- }
- }
3、定时查库,并更新任务
- package cloud.app.prod.home.quartz.mem;
- import javax.annotation.Resource;
- import org.quartz.CronScheduleBuilder;
- import org.quartz.CronTrigger;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
- import cloud.app.prod.home.common.FailException;
- import cloud.app.prod.home.mem.vo.MarketingActivitiesVO;
- import cloud.app.prod.home.utils.DSHUtils;
- /**
- * Author : YongBo Xie </br>
- * File Name: ScheduleRefreshDatabase.java </br>
- * Created Date: 2018年3月31日 下午3:58:08 </br>
- * Modified Date: 2018年3月31日 下午3:58:08 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- @EnableScheduling
- @Component
- public class ScheduleRefreshCron {
- @Resource(name = "marketingActivityJobDetail")
- private JobDetail jobDetail;
- @Resource(name = "marketingActivityJobTrigger")
- private CronTrigger cronTrigger;
- @Resource(name = "marketingActivityScheduler")
- private Scheduler scheduler;
- @Scheduled(fixedRate = 5000) // 每隔5s查库,并根据查询结果决定是否重新设置定时任务
- // @Scheduled(cron = "0 0 1 * * ?")
- public void scheduleUpdateCronTrigger() throws SchedulerException, FailException {
- CronTrigger trigger = (CronTrigger) scheduler.getTrigger(cronTrigger.getKey());
- String currentCron = trigger.getCronExpression();// 当前Trigger使用的
- String searchCron = "0 41 10 ? * *";// 从数据库查询出来的
- System.out.println(currentCron);
- System.out.println(searchCron);
- // 如果当前使用的cron表达式和从数据库中查询出来的cron表达式一致,则不刷新任务
- if (!currentCron.equals(searchCron)) {
- MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO();
- marketingActivitiesVO.setId(DSHUtils.generateUUID());
- // 表达式调度构建器
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
- // 按新的cronExpression表达式重新构建trigger
- trigger = (CronTrigger) scheduler.getTrigger(cronTrigger.getKey());
- trigger = trigger.getTriggerBuilder().withIdentity(cronTrigger.getKey())
- .withSchedule(scheduleBuilder).build();
- // 按新的trigger重新设置job执行
- scheduler.rescheduleJob(cronTrigger.getKey(), trigger);
- currentCron = searchCron;
- }
- }
- }
二、可传参任务
在Spring Boot中使用Quartz时,如果job涉及到调用其他自定义方法,需要通过定义Job Factory实现自动注入
传参关键代码:
1)、接收参数
- @Override
- protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
- JobDataMap dataMap = context.getJobDetail().getJobDataMap();
- MarketingActivitiesVO marketingActivitiesVO = (MarketingActivitiesVO) dataMap.get("marketingActivitiesVO");
- }
2)、传入参数
- // 创建一项作业
- JobDetail job = JobBuilder.newJob(ScheduleTask.class)
- .withIdentity("marketingActivityJob", "marketingActivityGroup")
- .build();
- // 设置参数
- MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO();
- marketingActivitiesVO.setId(DSHUtils.generateUUID());
- job.getJobDataMap().put("marketingActivitiesVO", marketingActivitiesVO);
1、自定义MyJobFactory类
- package cloud.app.prod.home.quartz;
- import org.quartz.spi.TriggerFiredBundle;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
- import org.springframework.scheduling.quartz.AdaptableJobFactory;
- import org.springframework.stereotype.Component;
- /**
- * Author : YongBo Xie </br>
- * File Name: MyJobFactory.java </br>
- * Created Date: 2018年4月2日 下午3:27:30 </br>
- * Modified Date: 2018年4月2日 下午3:27:30 </br>
- * Version: 1.0 </br>
- */
- @Component
- public class MyJobFactory extends AdaptableJobFactory {
- @Autowired
- private AutowireCapableBeanFactory capableBeanFactory;
- @Override
- protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
- // 调用父类的方法
- Object jobInstance = super.createJobInstance(bundle);
- // 进行注入
- capableBeanFactory.autowireBean(jobInstance);
- return jobInstance;
- }
- }
2、配置SchedulerFactoryBean
- package cloud.app.prod.home.quartz;
- import java.io.IOException;
- import java.util.Properties;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.config.PropertiesFactoryBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.io.ClassPathResource;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.quartz.SchedulerFactoryBean;
- import cloud.app.prod.home.quartz.MyJobFactory;
- /**
- * Author : YongBo Xie </br>
- * File Name: QuartzConfigration.java </br>
- * Created Date: 2018年3月31日 下午3:42:04 </br>
- * Modified Date: 2018年3月31日 下午3:42:04 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- @EnableScheduling
- public class QuartzConfigration {
- @Autowired
- private MyJobFactory myJobFactory;
- @Bean
- public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
- SchedulerFactoryBean factory = new SchedulerFactoryBean();
- // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
- factory.setOverwriteExistingJobs(true);
- // 延时启动,应用启动1秒后
- // factory.setStartupDelay(1);
- // 加载quartz数据源配置
- // factory.setQuartzProperties(quartzProperties());
- // 自定义Job Factory,用于Spring注入
- factory.setJobFactory(myJobFactory);
- return factory;
- }
- /**
- * 加载quartz数据源配置
- *
- * @return
- * @throws IOException
- */
- @Bean
- public Properties quartzProperties() throws IOException {
- PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
- propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
- propertiesFactoryBean.afterPropertiesSet();
- return propertiesFactoryBean.getObject();
- }
- }
3、执行任务类
- package cloud.app.prod.home.quartz.mem;
- import org.apache.log4j.Logger;
- import org.quartz.DisallowConcurrentExecution;
- import org.quartz.JobDataMap;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- import org.springframework.stereotype.Component;
- import cloud.app.prod.home.common.FailException;
- import cloud.app.prod.home.mem.vo.MarketingActivitiesVO;
- import cloud.app.prod.home.rabbitmq.mem.MarketingActivitieRabbitMqSender;
- /**
- * Author : YongBo Xie </br>
- * File Name: ScheduleTask.java </br>
- * Created Date: 2018年3月31日 下午3:37:43 </br>
- * Modified Date: 2018年3月31日 下午3:37:43 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- @Component // 此注解必加
- @EnableScheduling // 此注解必加
- @DisallowConcurrentExecution // 任务同步
- public class ScheduleTask extends QuartzJobBean {
- private static Logger logger = Logger.getLogger(ScheduleTask.class);
- @Autowired
- private MarketingActivitieRabbitMqSender marketingActivitieRabbitMqSender;
- @Override
- protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
- logger.info("execute activity");
- JobDataMap dataMap = context.getJobDetail().getJobDataMap();
- MarketingActivitiesVO marketingActivitiesVO = (MarketingActivitiesVO) dataMap.get("marketingActivitiesVO");
- logger.info("marketingActivitiesVO.id: " + marketingActivitiesVO.getId());
- try {
- logger.info("marketingActivitieRabbitMqSender: " + marketingActivitieRabbitMqSender);
- marketingActivitieRabbitMqSender.sendRabbitmqDirect(marketingActivitiesVO);
- } catch (FailException e) {
- e.printStackTrace();
- }
- }
- }
4、设置任务类
- package cloud.app.prod.home.quartz.mem;
- import java.util.Date;
- import org.apache.log4j.Logger;
- import org.quartz.CronScheduleBuilder;
- import org.quartz.CronTrigger;
- import org.quartz.DateBuilder;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.quartz.TriggerBuilder;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.scheduling.quartz.SchedulerFactoryBean;
- import org.springframework.stereotype.Component;
- import cloud.app.prod.home.common.FailException;
- import cloud.app.prod.home.mem.vo.MarketingActivitiesVO;
- import cloud.app.prod.home.utils.DSHUtils;
- /**
- * Author : YongBo Xie </br>
- * Project Name: DSH-SCRM </br>
- * Created Date: 2018年3月31日 下午3:58:08 </br>
- * Modified Date: 2018年3月31日 下午3:58:08 </br>
- * Version: 1.0 </br>
- */
- @Configuration
- @EnableScheduling
- @Component
- public class ScheduleRefreshCron {
- private static Logger logger = Logger.getLogger(ScheduleRefreshCron.class);
- @Autowired
- private SchedulerFactoryBean schedulerFactoryBean;
- @Scheduled(fixedRate = 5000) // 每隔5s查库
- // @Scheduled(cron = "0 0 1 * * ?")
- public void scheduleUpdateCronTrigger() throws FailException, SchedulerException {
- try{
- logger.info("----- scheduling job --------");
- String searchCron = "*/5 * * * * ?";// 从数据库查询出来的
- // 获取一个调度器
- // SchedulerFactory factory = new StdSchedulerFactory();
- // Scheduler scheduler = factory.getScheduler();
- Scheduler scheduler = schedulerFactoryBean.getScheduler();
- // 创建一项作业
- JobDetail job = JobBuilder.newJob(ScheduleTask.class)
- .withIdentity("marketingActivityJob", "marketingActivityGroup")
- .build();
- // 设置参数
- MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO();
- marketingActivitiesVO.setId(DSHUtils.generateUUID());
- job.getJobDataMap().put("marketingActivitiesVO", marketingActivitiesVO);
- // 作业的执行时间(当前时间的下一分钟)
- Date runTime = DateBuilder.evenMinuteDate(new Date());
- // 创建一个触发器
- CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger()
- .withIdentity("marketingActivityTrigger", "marketingActivityGroup")
- .startAt(runTime) //该触发器将在runTime时执行作业
- .endAt(new Date(System.currentTimeMillis()+5*1000+60*1000)) //该触发器将在runTime时结束作业
- .withSchedule(CronScheduleBuilder.cronSchedule(searchCron)) // 具体执行时间
- .build();
- // 告诉调度器使用该触发器来安排作业
- scheduler.scheduleJob(job, trigger);
- // 启动调度器
- scheduler.start();
- logger.info("------ started scheduler -------");
- logger.info("------ waiting 2 minutes ------");
- Thread.sleep(2*60*1000);
- logger.info("------- shutting down ------");
- // 关闭调度器
- scheduler.shutdown(true);
- logger.info("------- shutdown complete -------");
- }catch(Exception e){
- logger.error(DSHUtils.formatException(e));
- throw new FailException(e.getMessage());
- }
- }
- }
springboot-quartz普通任务与可传参任务的更多相关文章
- spring-quartz普通任务与可传参任务
两者区别与作用: 普通任务:总调度(SchedulerFactoryBean)--> 定时调度器(CronTriggerFactoryBean) --> 调度明细自定义执行方法bean(M ...
- SpringBoot系列: Java应用程序传参和SpringBoot参数文件
===========================向java 程序传参的几种形式:===========================1. 使用 OS 环境变量. 这个不推荐. 2. 使用JVM ...
- springboot对传参的拦截统一处理
在学习某网<java秒杀系统方案优化>的课程中,学到了一种springboot对传参的拦截统一处理的方式,特记录一下. 如后台方法一般需要根据token从Session中获取User对象, ...
- SpringBoot 2.x (2):请求和传参
其实请求和传参这些知识属于SpringMVC 不过这也属于必须掌握的知识,巩固基础吧 GET请求: 以第一篇文章自动的方式创建SpringBoot项目: 然后新建Controller: package ...
- SpringBoot传参方式
地址传参 1.创建一个Action类 package com.lion.action; import org.springframework.stereotype.Controller; import ...
- SpringBoot 处理 POST Json 传参枚举
在 Spring 框架中对枚举类型的序列化/反序列化是有限制的. 假设如下面这样在某些情况下就不能正常工作: 123456789 public enum PayChannelEnum implemen ...
- Docker 如何动态给SpringBoot项目传参
关于SpringBoot配置数据源 在项目开发中,我们往往需要配置多套不同的配置环境例如:本地开发.测试环境.部署环境.每一个环境的数据源配置可能都不同,因此需要写不同的数据源配置.如果用Docker ...
- springboot实现xml传参和返回值
1.新建maven工程xml-bean-convert pom.xml如下 <?xml version="1.0" encoding="UTF-8"?&g ...
- 二十一、springboot之定制URL匹配规则(项目中遇到的问题:get方式传参,带有小数点,被忽略)
一.问题描述: get方式传参,在传送价格,积分时(带有小数点),debug后台微服务接受到的参数,却不带小数点,如:price是0.55,后台接受后却是0 二.解决 在WebConfiguratio ...
随机推荐
- TCP:三次握手,URG、ACK、PSH、RST、SYN、FIN 含义
http://blog.csdn.net/wudiyi815/article/details/8505726 TCP:SYN ACK FIN RST PSH URG简析 三次握手Three-way ...
- SpringMVC知识点总结一(非注解方式的处理器与映射器配置方法)
一.SpringMVC处理请求原理图(参见以前博客) 1. 用户发送请求至前端控制器DispatcherServlet 2. DispatcherServlet收到请求调用HandlerMappi ...
- 学习csv
1.csv文件读取,csv文件是常用的数据存储格式之一,我们使用Python模块来处理csv文件,这是一个天气信息表 import csv from matplotlib import pyplot ...
- 【转载】文件上传Expected MultipartHttpServletRequest: is a MultipartResolver错误解决
引入包commons-fileupload-*.jar,版本号可以根据项目情况调整: 在spring mvc配置文件中增加配置,文件大小限制可根据项目情况调整: <!-- 上传文件拦截,设置最大 ...
- DOClever线下部署安装说明文档
先本地要安装node环境,推荐6.10.0版本 到nodejs官网进行下载window版本进行安装,这里就不做说明了 接下来我们开始安装mongodb,首先下载mongodb 下载完成后我们一路 ...
- Redis 原子操作INCR
The content below come from http://try.redis.io/ There is something special about INCR. Why do we pr ...
- hadoop-hdp-ambari离线安装记录
一.系统准备 1. 创建user——ambari 2.关闭防火墙 redhat6: chkconfig iptables off /etc/init.d/iptables stop redhat7: ...
- 【Codeforces Global Round 1 A】Parity
[链接] 我是链接,点我呀:) [题意] 给你一个k位数b进制的进制转换. 让你求出来转成10进制之后这个数字是奇数还是偶数 [题解] 模拟一下转换的过程,加乘的时候都记得对2取余就好 [代码] im ...
- (40). springboot + devtools(热部署)【从零开始学Spring Boot】
我们之前在在()Spring Boot热部署[从零开始学Spring Boot] (http://412887952-qq-com.iteye.com/blog/2291518 )讲过通过使用spri ...
- DSP广告系统架构及关键技术解析(转)
广告和网络游戏是互联网企业主要的盈利模式 广告是广告主通过媒体以尽可能低成本的方式与用户达成接触的商业行为.也就是说按照某种市场意图接触相应人群,影响其中潜在用户,使其选择广告主产品的几率增加,或对广 ...