
xxl-job是通过一个中心式的调度平台,调度多个执行器执行任务,调度中心通过DB锁保证集群分布式调度的一致性,这样扩展执行器会增大DB的压力,但是如果实际上这里数据库只是负责任务的调度执行。但是如果没有大量的执行器的话和任务的情况,是不会造成数据库压力的。实际上大部分公司任务数,执行器并不多(虽然面试经常会问一些高并发的问题)。
相对来说,xxl-job中心式的调度平台轻量级,开箱即用, *** 作简易,上手快,与SpringBoot有非常好的集成,而且监控界面就集成在调度中心,界面又简洁,对于企业维护起来成本不高,还有失败的邮件告警等等。这就使很多企业选择xxl-job做调度平台。
二、过程- 新建一个SpringBoot项目,或使用现有的SpringBoot项目;
- maven配置pom.xml,导入相关的依赖
- 编写application.yml,如:项目路径名及端口,mybatisplus配置,mysql多数据源配置。
- 新建DataSourceContextHolder 用于设置,获取,清空 当前线程内的数据源变量。
- 新建 MultipleDataSource 实现 AbstractRoutingDataSource 类。重写determineCurrentLookupKey(),通过DataSourceContextHolder 获取数据源变量,用于当作lookupKey取出指定的数据源。
- 新建DataSourceEnum 用于存放数据源名称。
- 新建注解 DataSource,用于下面aop类中当作切入点来选择数据源。
- 编写aop类 --> DataSourceAspect.java
- 新建并配置以下的三个类
DruidConfiguration:
StatViewServlet 和 WebStatFilter Druid监控配置和监控过滤器。
MybatisplusConfiguration:
mybatisplus 分页插件,SQL执行效率插件;
数据源Bean,MultipleDataSource 注入;
SqlSessionFactory注入;SwaggerConfiguration:
自动生成的接口文档,不需要频繁更新接口文档,保证接口文档与代码的一致。
- 测试mybatis-plus+多数据源配置。
1.新建一个SpringBoot项目,或使用现有的SpringBoot项目;
2.maven配置pom.xml,导入相关的依赖
1.1.22 2.7.0 mysql mysql-connector-javaruntime org.projectlombok lomboktrue com.baomidou mybatis-plus-boot-starter3.1.0 com.alibaba druid-spring-boot-starter${druid.version} io.springfox springfox-swagger2${swagger.version} io.springfox springfox-swagger-ui${swagger.version} org.springframework.boot spring-boot-starter-aopcom.baomidou mybatis-plus-extension3.1.0
3.编写application.yml,如:项目路径名及端口,mybatisplus配置,mysql多数据源配置。
server:
servlet:
context-path: /ssm-zyy
spring:
datasource:
druid:
db1:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/student?serverTimezone=UTC
initialSize: 5
minIdle: 5
maxActive: 20
db2:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/teacher?serverTimezone=UTC
initialSize: 5
minIdle: 5
maxActive: 20
mybatis-plus:
mapper-locations: classpath:/mapper
public class DataSourceContextHolder {
private static final ThreadLocal contextHolder = new InheritableThreadLocal<>();
public static void setDataSource(String db){
contextHolder.set(db);
}
public static String getDataSource(){
return contextHolder.get();
}
public static void clear(){
contextHolder.remove();
}
}
5.新建 MultipleDataSource 实现 AbstractRoutingDataSource 类。重写determineCurrentLookupKey(),通过DataSourceContextHolder 获取数据源变量,用于当作lookupKey取出指定的数据源。
package com.xxl.datasource.multiple;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
6.新建DataSourceEnum 用于存放数据源名称。
package com.xxl.datasource.enums;
public enum DataSourceEnum {
DB1("db1"),DB2("db2");
private String value;
DataSourceEnum(String value){this.value=value;}
public String getValue() {
return value;
}
}
7.新建注解 DataSource,用于下面aop类中当作切入点来选择数据源。
package com.xxl.datasource.annotation;
import com.xxl.datasource.enums.DataSourceEnum;
import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface DataSource {
DataSourceEnum value() default DataSourceEnum.DB1;
}
8.编写aop类 --> DataSourceAspect.java
package com.xxl.datasource.aop;
import com.xxl.datasource.annotation.DataSource;
import com.xxl.datasource.multiple.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
@Order(-1)
public class DataSourceAspect {
@Pointcut("@within(com.xxl.datasource.annotation.DataSource) || @annotation(com.xxl.datasource.annotation.DataSource)")
public void pointCut(){
}
@Before("pointCut() && @annotation(dataSource)")
public void doBefore(DataSource dataSource){
log.info("选择数据源---"+dataSource.value().getValue());
DataSourceContextHolder.setDataSource(dataSource.value().getValue());
}
@After("pointCut()")
public void doAfter(){
DataSourceContextHolder.clear();
}
}
9.新建并配置以下的三个类
DruidConfiguration:
StatViewServlet 和 WebStatFilter Druid监控配置和监控过滤器。
package com.xxl.config; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DruidConfiguration { @Bean public ServletRegistrationBean startViewServlet(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid @Bean public FilterRegistrationBean statFilter(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); //添加过滤规则 filterRegistrationBean.addUrlPatterns(" @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 开启 PageHelper 的支持 // paginationInterceptor.setLocalPage(true); return paginationInterceptor; } @Bean @Profile({"dev","qa"})// 设置 dev test 环境开启 public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(1000); performanceInterceptor.setFormat(true); return performanceInterceptor; } @Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.druid.db1" ) public DataSource db1() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.druid.db2" ) public DataSource db2() { return DruidDataSourceBuilder.create().build(); } @Bean @Primary public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2) { MultipleDataSource multipleDataSource = new MultipleDataSource(); Map< Object, Object > targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceEnum.DB1.getValue(), db1); targetDataSources.put(DataSourceEnum.DB2.getValue(), db2); //添加数据源 multipleDataSource.setTargetDataSources(targetDataSources); //设置默认数据源 multipleDataSource.setDefaultTargetDataSource(db1); return multipleDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2())); //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml")); MybatisConfiguration configuration = new MybatisConfiguration(); //configuration.setDefaultscriptingLanguage(MybatisXMLLanguageDriver.class); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor() paginationInterceptor() //添加分页功能 }); //sqlSessionFactory.setGlobalConfig(globalConfiguration()); return sqlSessionFactory.getObject(); } }SwaggerConfiguration:
自动生成的接口文档,不需要频繁更新接口文档,保证接口文档与代码的一致。
package com.xxl.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.documentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; //http://localhost:8083/ssm-zyy/swagger-ui.html @Configuration @EnableSwagger2 public class SwaggerConfiguration { @Bean public Docket createRestApi() { return new Docket(documentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.xxl.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo(){ return new ApiInfoBuilder() .title("多数据源 SpringBoot+MyBatis-PLUS 测试服务") .description("多数据源 SpringBoot+MyBatis-PLUS 测试文档") .termsOfServiceUrl("http://www.baidu.com") .version("1.0") .build(); } }
10.测试mybatis-plus+多数据源配置。
实体类
package com.xxl.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Api("学生实体对象")
@Data
@TableName("t_student")
public class Student {
@ApiModelProperty("学生id")
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty("学生姓名")
private String name;
@ApiModelProperty("学生年龄")
private Integer age;
@ApiModelProperty("学生班级")
private String classname;
}
package com.xxl.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Api("老师实体对象")
@Data
@TableName("t_teacher")
public class Teacher {
@ApiModelProperty("老师id")
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty("老师姓名")
private String name;
@ApiModelProperty("老师年龄")
private Integer age;
@ApiModelProperty("老师所教学科")
private String subject;
}
Mapper
package com.xxl.mapper; import com.baomidou.mybatisplus.core.mapper.baseMapper; import com.xxl.entity.Student; public interface StudentMapper extends baseMapper{ }
package com.xxl.mapper; import com.baomidou.mybatisplus.core.mapper.baseMapper; import com.xxl.entity.Teacher; public interface TeacherMapper extends baseMapper{ }
Service
package com.xxl.service; import com.baomidou.mybatisplus.extension.service.IService; import com.xxl.entity.Student; public interface StudentService extends IService{ }
package com.xxl.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xxl.entity.Student; import com.xxl.mapper.StudentMapper; import com.xxl.service.StudentService; import org.springframework.stereotype.Service; @Service public class StudentServiceImpl extends ServiceImplimplements StudentService { }
package com.xxl.service; import com.baomidou.mybatisplus.extension.service.IService; import com.xxl.entity.Teacher; public interface TeacherService extends IService{ }
package com.xxl.service.impl; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xxl.datasource.annotation.DataSource; import com.xxl.datasource.enums.DataSourceEnum; import com.xxl.entity.Teacher; import com.xxl.mapper.TeacherMapper; import com.xxl.service.TeacherService; import org.springframework.stereotype.Service; import java.io.Serializable; import java.util.List; @Service public class TeacherServiceImpl extends ServiceImplimplements TeacherService { @Override @DataSource(DataSourceEnum.DB2) public boolean save(Teacher entity) { return super.save(entity); } @Override @DataSource(DataSourceEnum.DB2) public boolean removeById(Serializable id) { return super.removeById(id); } @Override @DataSource(DataSourceEnum.DB2) public boolean updateById(Teacher entity) { return super.updateById(entity); } @Override @DataSource(DataSourceEnum.DB2) public Teacher getById(Serializable id) { return super.getById(id); } @Override @DataSource(DataSourceEnum.DB2) public List list(Wrapper queryWrapper) { return super.list(queryWrapper); } @Override @DataSource(DataSourceEnum.DB2) public List list() { return super.list(); } @Override @DataSource(DataSourceEnum.DB2) public IPage page(IPage page, Wrapper queryWrapper) { return super.page(page,queryWrapper); } @Override @DataSource(DataSourceEnum.DB2) public IPage page(IPage page) { return super.page(page); } }
VO
package com.xxl.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("学生vo")
public class StudentVo {
@ApiModelProperty("学生姓名")
private String name;
@ApiModelProperty("学生年龄")
private Integer age;
@ApiModelProperty("学生班级")
private String classname;
}
package com.xxl.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("老师vo")
public class TeacherVo {
@ApiModelProperty("老师姓名")
private String name;
@ApiModelProperty("老师年龄")
private Integer age;
@ApiModelProperty("老师教的学科")
private String subject;
}
Controller
package com.xxl.controller;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxl.entity.Student;
import com.xxl.service.StudentService;
import com.xxl.vo.StudentVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api("对学生表CRUD")
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@ApiOperation("添加学生")
@PostMapping("/add")
public String add(@RequestBody StudentVo student){
Student stu = new Student();
stu.setName(student.getName());
stu.setAge(student.getAge());
stu.setClassname(student.getClassname());
return studentService.save(stu)?"添加成功":"添加失败";
}
@ApiOperation("删除学生")
@DeleteMapping("/delete/{id}")
public String delete(@ApiParam("学生的主键id")@PathVariable(value = "id") Integer id){
return studentService.removeById(id)?"删除成功":"删除失败";
}
@ApiOperation("修改学生")
@PostMapping("/update")
public String update(@RequestBody Student student){
return studentService.updateById(student)?"修改成功":"修改失败";
}
@ApiOperation(value = "查询学生")
@GetMapping("/list")
public List list(){
Wrapper wrapper = new QueryWrapper<>();
return studentService.list(wrapper);
}
}
package com.xxl.controller;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxl.entity.Teacher;
import com.xxl.service.TeacherService;
import com.xxl.vo.TeacherVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api("对老师表CRUD")
@RestController
@RequestMapping("/teacher")
public class TeacherController {
@Autowired
private TeacherService teacherService;
@ApiOperation(value = "添加老师")
@PostMapping("/add")
public String add(@RequestBody TeacherVo teacher){
Teacher tea = new Teacher();
tea.setName(teacher.getName());
tea.setAge(teacher.getAge());
tea.setSubject(teacher.getSubject());
return teacherService.save(tea)?"添加成功":"添加失败";
}
@ApiOperation("删除老师")
@DeleteMapping("/delete/{id}")
public String delete(@ApiParam("老师的主键id")@PathVariable(value = "id") Integer id){
return teacherService.removeById(id)?"删除成功":"删除失败";
}
@ApiOperation("修改老师")
@PostMapping("/update")
public String update(@RequestBody Teacher teacher){
return teacherService.updateById(teacher)?"修改成功":"修改失败";
}
@ApiOperation(value = "查询老师")
@GetMapping("/list")
public List list(){
Wrapper wrapper = new QueryWrapper<>();
return teacherService.list(wrapper);
}
}
11.效果
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)