Giới thiệu
Tôi sử dụng xxl-job để quản lý tác vụ nền, chủ yếu là để giải quyết nhanh vấn đề HA của các tác vụ theo lịch trình. Mã dự án không lớn, các chức năng được sắp xếp hợp lý và không có sự phụ thuộc đặc biệt. Vì dự án này được sử dụng trong sản phẩm nên tôi đã dành một chút thời gian vào buổi sáng để nghiên cứu cơ chế hoạt động. Viết ra những gì tôi thấy.
- Thư viện dự án
- https://github.com/xuxueli/xxl-job
- http://gitee.com/xuxueli0323/xxl-job
- Tài liệu https://www.xuxueli.com/xxl-job/
môi trường
com.xuxueli xxl-job-core ${phiên bản ổn định mới nhất}
Cần phải chạy JDK1.8 và MySQL5.7.
Cấu trúc cơ sở dữ liệu
- Thư viện mã hóa utf8mb4_unicode_ci
- Bảng: xxl_job_group
Nhóm tác vụ, tên nhóm, chỉ hỗ trợ một cấp độ nhóm, trường address_list hỗ trợ nhiều địa chỉ kết thúc thực thi, được phân tách bằng dấu phẩy
- Bảng: xxl_job_info
Bảng tổng hợp tác vụ, ghi lại chi tiết tác vụ, chi tiết lịch trình và cài đặt cảnh báo
- Bảng: xxl_job_log
Nhật ký thực hiện từng tác vụ
- Bảng: xxl_job_log_report
Kết quả thống kê hàng ngày về nhật ký thực hiện
- Bảng: xxl_job_logglue
- Bảng: xxl_job_registry
Được sử dụng để đăng ký người thực hiện tác vụ, nhóm bản ghi: nhóm, khóa: tên, giá trị: địa chỉ giao diện. Tên có thể được lặp lại và địa chỉ giao diện sẽ được thêm vào trường đăng ký trong bảng nhóm tác vụ
- Bảng: xxl_job_user
Kiểm soát đăng nhập đơn giản, không liên kết với các bảng khác
- Bảng: xxl_job_lock
Bảng trường đơn, được sử dụng để khóa nhằm tránh xung đột trong quá trình đồng thời
Cấu trúc mã
- Dự án sử dụng các thành phần chung, MyBatis, FreeMarker, Bootstrap và phiên bản hiện tại dựa trên SpringBoot 2.6.7
- Mô-đun xxl-job-admin đang chạy trực tuyến, cung cấp các dịch vụ như đăng ký kết thúc thực thi, khởi tạo tác vụ và ghi nhật ký.
- Dự án cần triển khai xxl-job-executor, một ví dụ được cung cấp trong dự án
Cấu trúc tệp dự án như sau.
├── -doc │ ──- ──-JOB │ │ └──ADMIN │ │ └──Impl │ └─hn thế giới JAVA │ ├──XXL-job-lõi # gói jar công cộng, mô-đun phụ thuộc nội bộ │ │ ├─hna │ │ │ └───resources │ └───test │ └───java └───xxl-job-executor-sample-springboot # Ví dụ về việc sử dụng lớp thực thi của SpringBoot └───src ├───main │ ├───java │ └───resources └──test
Cơ chế hoạt động
Người thực hiện cần chuẩn bị những thông tin sau.
-
adminĐịa chỉ máy chủ, ví dụ http://127.0.0.1:8080/xxl-job-admin .
-
accessToken có vẻ là mã thông báo máy chủ, cần được xác minh khi gọi api/registry phía máy chủ, api/registryRemove và các hoạt động khác.
-
appname Tên kết thúc thực thi.
-
address là địa chỉ kết thúc thực thi và ip:port được chọn. Nếu tồn tại, nó sẽ ghi đè lên ip:port.
-
ip thực hiện kết thúc IP.
-
cổng Thực hiện kết thúc dịch vụ cổng.
-
Sau khi quá trình thực thi bắt đầu, nó sẽ tự đăng ký với máy chủ và chờ lệnh gọi lại.
-
Việc thực thi tác vụ được bắt đầu thông qua XxlJobTrigger.processTrigger(), chuẩn bị các tham số và chọn một địa chỉ trong nhóm.
-
Nhận ExecutorBiz theo địa chỉ này và gọi executorBiz.run() để thực thi tác vụ.
-
Máy chủ: thông qua ExecutorBizClient.
- Gọi
XxlJobRemotingUtil.postBody(addressUrl + "chạy", accessToken, thời gian chờ, triggerParam, String.class);
- TRONG
Mã truy cập
Đây là accessToken của máy chủ.
-
Phía thực hiện: thông qua ExecutorBizImpl.run().
- Gọi
XxlJobExecutor.loadJobHandler(triggerParam.getExecutorHandler());
Nhận phương pháp XxlJob
- vượt qua
XxlJobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason)
thực hiện
Các kịch bản không phải mùa xuân
Bằng cách gọi FrameLessXxlJobConfig.getInstance().initXxlJobExecutor(), XxlJobSimpleExecutor được khởi tạo và đăng ký vào máy chủ xxl_job.
Kịch bản mùa xuân
- hiện hữu
@Cấu hình
Trong XxlJobSpringExecutor như một @Đậu
Thêm vào ngữ cảnh Spring
- XxlJobSpringExecutor là một lớp con của XxlJobExecutor và triển khai
Khởi tạo thông minhSingleton
Giao diện afterSingletonsKhởi tạo()
phương pháp
- hiện hữu
afterSingletonsKhởi tạo()
Phương pháp
- Gọi initJobHandlerMethodRepository(), trong phương pháp này, tìm tất cả
@XxlJob
Phương pháp chú thích
- vượt qua
đăng kýJobHandler()
, Sẽ @XxlJob
Phương pháp được thêm vào private static ConcurrentMap jobHandlerRepository
- Gọi
XxlJobExecutor.bắt đầu()
, hãy đăng ký bản thân vào máy chủ xxl_job
Dịch vụ gọi từ xa
xxl_job không sử dụng cơ chế dịch vụ của Spring, nhưng triển khai một dịch vụ lắng nghe IP+port được chỉ định bên trong. Lớp tương ứng của triển khai này là EmbedServer, dịch vụ dựa trên Netty và mã lõi là.
// khởi động máy chủ ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel channel) throws Exception { channel.pipeline() .addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS)) // đánh bại 3N, đóng nếu nhàn rỗi .addLast(new HttpServerCodec()) .addLast(new HttpObjectAggregator(5 * 1024 * 1024)) // hợp nhất yêu cầu và phản hồi thành FULL .addLast(new EmbedHttpServerHandler(executorBiz, accessToken, bizThreadPool)); } }) .childOption(ChannelOption.SO_KEEPALIVE, đúng);
Dòng mã này đăng ký phương thức XxlJob nội bộ.
.addLast(EmbedHttpServerHandler mới(executorBiz, accessToken, bizThreadPool)
Khi xử lý yêu cầu từ xa, trong đoạn mã sau, phương thức XxlJob được gọi thông qua executorBiz.run(triggerParam).
Đối tượng riêng tư process(HttpMethod httpMethod, String uri, String requestData, String accessTokenReq) { //... // ánh xạ dịch vụ thử { chuyển đổi (uri) { trường hợp "/beat": trả về executorBiz.beat(); trường hợp "/idleBeat": IdleBeatParam idleBeatParam = GsonTool.fromJson(requestData, IdleBeatParam.class); trả về executorBiz.idleBeat(idleBeatParam); trường hợp "/run": TriggerParam triggerParam = GsonTool.fromJson(requestData, TriggerParam.class); trả về executorBiz.run(triggerParam); trường hợp "/kill": KillParam killParam = GsonTool.fromJson(requestData, KillParam.class); trả về executorBiz.kill(killParam); trường hợp "/log": LogParam logParam = GsonTool.fromJson(requestData, LogParam.class); trả về executorBiz.log(logParam); mặc định: trả về new ReturnT(ReturnT.FAIL_CODE, "yêu cầu không hợp lệ, không tìm thấy uri-mapping(" + uri + ")."); } } catch (Ngoại lệ e) { //... }
Cơ chế khóa
Điều này đạt được thông qua select ... để cập nhật. Bảng này không được đưa vào MyBatis mà là vào JobScheduleHelper.
preparedStatement = conn.prepareStatement( "chọn * từ xxl_job_lock nơi lock_name = 'schedule_lock' để cập nhật" ); preparedStatement.execute();
Nhận khóa và mở khóa ở cuối phương pháp.
// đóng PreparedStatement nếu (null != preparedStatement) { thử { preparedStatement.close(); } bắt (SQLException e) { nếu (!scheduleThreadToStop) { logger.error(e.getMessage(), e); } } }
Cuối cùng, bài viết này về phân tích mã Java của tác vụ lập lịch xxl-job đã kết thúc tại đây. Nếu bạn muốn biết thêm về phân tích mã Java của tác vụ lập lịch xxl-job, vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!