Java学习笔记:定时任务调度工具之Quartz

简介: Java学习笔记:定时任务调度工具之Quartz

Quartz官网

http://www.quartz-scheduler.org/

特点

  1. 强大的调度功能
  2. 灵活的应用方式
  3. 分布式和集群能力

主要用到的设计模式

  1. Builder 模式
  2. Factory 模式
  3. 组件模式
  4. 链式写法

三个核心概念

  1. 调度器
  2. 任务
  3. 触发器


Quartz 体系结构

JobDetail
scheduler
trigger
    -SimpleTrigger
    -CronTrigger

重要组成

Job
JobDetail
JobBuilder
JobStore
Trigger
TriggerBuilder
ThreadPool
Scheduler
Calendar
监听器
JobListener
TriggerListener
SchedulerListener

Quartz 实例

依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
    <scope>compile</scope>
</dependency>

定义任务 MyJob.java

package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(dateFormat.format(new Date()));
    }
}

调度任务 QuartzDemo.java

package timer;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建JobDetail
        JobDetail jobDetail = JobBuilder
                .newJob(MyJob.class)
                .withIdentity("myJob", "group1")
                .build();
        // 每2s执行一次,无限循环
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
                .simpleSchedule()
                .withIntervalInSeconds(2)
                .repeatForever();
        // 创建Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "group1")
                .startNow()
                .withSchedule(scheduleBuilder)
                .build();
        // 通过工厂方法创建Scheduler实例
        SchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail, trigger);
    }
}

Job 和 JobDetail

1、Job 源码:

package org.quartz;
public interface Job {
    void execute(JobExecutionContext context)
        throws JobExecutionException;
}

2、Job 的生命周期:


每次调度器执行 Job 时,调用 execute 方法前会创建一个新的 Job 实例

调用完成后,关联的 Job 对象实例会被释放,释放的实例会被垃圾回收机制回收


3、JobDetail:


JobDetail 为 Job 实例提供了许多设置属性,以及 JobDataMap 成员变量属性,

它用来存储特定 Job 实例的状态信息,调度器需要借助 JobDetail 对象来添加 Job 实例


4、JobDetail 重要属性

name
group 默认值DEFAULT
jobClass
jobDataMap
// 创建JobDetail
JobDetail jobDetail = JobBuilder
        .newJob(MyJob.class)
        .withIdentity("myJob", "group1")
        .build();
// 打印jobDetail属性
System.out.println(jobDetail.getKey().getName()); // myJob
System.out.println(jobDetail.getKey().getGroup()); // group1
System.out.println(jobDetail.getJobClass().getName()); // timer.MyJob

JobExecutionContext & JobDataMap

1、JobExecutionContext:


Scheduler 给 Job 传递参数


2、JobDataMap:


可以装载任何可序列化的数据对象

实现了 Map 接口


设置 JobDataMap 部分代码

// 创建JobDetail
JobDetail jobDetail = JobBuilder
        .newJob(MyJob.class)
        .withIdentity("myJob", "group1")
        .usingJobData("name", "jobDetail")
        .build();
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
        .simpleSchedule()
        .withIntervalInSeconds(2)
        .repeatForever();
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startNow()
        .usingJobData("name", "trigger")
        .withSchedule(scheduleBuilder)
        .build();

获取 JobDataMap

方法一:直接从 JobDataMap 对象中获取

package timer;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取 jobkey
        JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
        System.out.println(jobKey.getName()); // myJob
        System.out.println(jobKey.getGroup()); // group1
        // 获取JobDetail的DataMap
        JobDataMap jobDetailDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        System.out.println(jobDetailDataMap.getString("name"));
        // jobDetail
        // 获取Trigger的DataMap
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
        System.out.println(triggerDataMap.getString("name"));
        // trigger
        // 获取合并后的DataMap
        JobDataMap dataMap = jobExecutionContext.getMergedJobDataMap();
        System.out.println(dataMap.getString("name"));
        // trigger
    }
}

方法二:定义同名变量获取

package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(this.name);
    }
}

Trigger

Trigger 是触发器,用来告诉调度程序作业什么时候触发

触发器通用属性

JobKey: Job 实例的标识,触发器被触发时,指定的 job 实例会执行
StartTime:触发器的时间表首次被触发的时间,类型是 Java.util.Date
EndTime:触发器不再被触发的时间 Java.util.Date

设置部分代码

// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 获取6秒后的时间
Date endDate = new Date();
endDate.setTime(endDate.getTime() + 3000);
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startAt(startDate)
        .endAt(endDate)
        .usingJobData("name", "trigger")
        .withSchedule(scheduleBuilder)
        .build();

Job 中获取 Trigger 数据

package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Trigger;
import java.text.SimpleDateFormat;
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Trigger trigger = jobExecutionContext.getTrigger();
        // 获取开始时间和结束时间
        System.out.println(dateFormat.format(trigger.getStartTime()));
        System.out.println(dateFormat.format(trigger.getEndTime()));
        // 获取JobKey
        System.out.println(trigger.getJobKey().getName());
        System.out.println(trigger.getJobKey().getGroup());
    }
}

SimpleTrigger

指定时间段内执行一次作业任务

或者在指定的时间间隔内多次执行作业任务

任务

package timer;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(dateFormat.format(new Date()));
    }
}

示例 1

// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 3秒钟之后执行一次
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startAt(startDate)
        .build();

示例 2

// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000);
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
        .simpleSchedule()
        .withIntervalInSeconds(2)
        .withRepeatCount(3);
// 3s之后执行第一次,之后每隔2s执行一次,重复3次
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startAt(startDate)
        .withSchedule(scheduleBuilder)
        .build();

示例 3

// 获取3秒后的时间
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 3000L);
// 获取6秒后的时间
Date endDate = new Date();
endDate.setTime(endDate.getTime() + 6000L);
// 每2s执行一次,无限循环
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
        .simpleSchedule()
        .withIntervalInSeconds(2)
        .withRepeatCount(3);
// 3s之后执行第一次,之后每隔2s执行一次,6秒之后结束
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startAt(startDate)
        .endAt(endDate)
        .withSchedule(scheduleBuilder)
        .build();

注意:


重复次数可以为 0、正整数、SimpleTrigger.REPEAT_INDEFINITELY

重复执行间隔必须为 0 或长整数

一旦执行了 endTime 参数,那么会覆盖重复次数参数的效果

CronTrigger

基于日历的作业调度器,而不是像 SimpleTrigger 那样精确指定时间间隔,较为常用

格式:

秒 分 时 日 月 周 年

特殊符号说明

, 或 10,12
- 区间 10-12
/ 每 */5
* 所有值 *
? 不指定

提示

  1. L 和 W 可以组合使用
  2. 周字段不区分大小写 mon 与 MON 相同
  3. 利用在线生成工具

示例

// 每2秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ? *"))
                .build();

Scheduler

StdSchedulerFactory

配置参数一般存储在 quartz.properties

主要函数

// 将job和trigger注册到scheduler
Date scheduleJob(JobDetail jobDetail, Trigger trigger)
// 启动
void start()
// 暂停
void standby()
// 关闭
// true 等待所有任务执行完成再关闭
// false 直接关闭
void shutdown()

quartz.properties

文档位置和加载顺序

jar 包下有默认配置

组成部分

  1. 调度器属性
  2. 线程池属性
  3. 作业存储位置
  4. 插件配置

SpringMVC 整合 Quartz

新建 maven webapp

依赖

webmvc
context
aop
core

配置 Quartz 的两种方式:

  1. MethodInvokingJobDetailFactoryBean 适合调用特定 bean 方法时很方便
  2. JobDetailFactoryBean 支持传入一些参数

项目结构

$ tree -I target
.
├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── mouday
│       │           ├── controller
│       │           │   └── IndexController.java
│       │           └── quartz
│       │               ├── ComplexJob.java
│       │               └── SimpleJob.java
│       ├── resources
│       │   └── dispatcher-servlet.xml
│       └── webapp
│           ├── WEB-INF
│           │   └── web.xml
│           └── index.jsp

1、pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>spring-mvc-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>5.2.6.RELEASE</spring.version>
    </properties>
    <build>
        <finalName>springquartz</finalName>
        <plugins>
            <!-- tomcat7插件 maven 命令 tomcat7:run 启动项目-->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                    <uriEncoding>UTF-8</uriEncoding>
                    <!--添加忽略war包检查标签,则可以让tomcat7:run指令正常启动tomcat-->
                    <ignorePackaging>true</ignorePackaging>
                    <contextFile>src/main/webapp/WEB-INF/web.xml</contextFile>
                    <contextReloadable>true</contextReloadable>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- 需要 context-support tx 的支持-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

2、src/main/webapp/index.jsp

<html>
    <body>
        <h2>Hello World!</h2>
    </body>
</html>

3、src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <!-- 配置分发器 默认加载配置文件:名字-servlet.xml -->
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定配置文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:dispatcher-servlet.xml</param-value>
    </init-param>
    <!-- 表示容器再启动时立即加载servlet -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 处理所有URL -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

4、src/main/resources/dispatcher-servlet.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
    <!--防止中文乱码-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html; charset=utf-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
    <!-- 添加注解驱动-->
    <mvc:annotation-driven/>
    <!-- 默认扫描包路径-->
    <context:component-scan base-package="com.mouday"/>
    <!-- view-controller 可以直接不通过controller处理request,转发到view-->
    <mvc:view-controller path="/" view-name="index"/>
    <!-- 渲染器-->
    <bean id="jspViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <!-- 结果视图的前缀-->
        <property name="prefix" value="/"/>
        <!-- 结果视图的后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--配置Quartz-->
    <bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="simpleJob"/>
        <property name="targetMethod" value="sayHello"/>
    </bean>
    <bean id="complexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.mouday.quartz.ComplexJob"/>
        <property name="jobDataMap">
            <map>
                <entry key="name" value="Tom"/>
            </map>
        </property>
        <property name="Durability" value="true"/>
    </bean>
    <!--一s之后执行,每隔2s执行一次-->
    <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail"  ref="simpleJobDetail"/>
        <property name="startDelay" value="1000"/>
        <property name="repeatInterval" value="2000"/>
    </bean>
    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="complexJobDetail"/>
        <property name="cronExpression" value="0/3 * * * * ? *"/>
    </bean>
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobDetails">
            <list>
                <ref bean="simpleJobDetail"/>
                <ref bean="complexJobDetail"/>
            </list>
        </property>
        <property name="triggers">
            <list>
                <ref bean="simpleTrigger"/>
                <ref bean="cronTrigger"/>
            </list>
        </property>
    </bean>
</beans>

5、src/main/java/com/mouday/controller/IndexController.java

package com.mouday.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * 仅用于SpringMVC服务测试
 */
@Controller
public class IndexController {
    @GetMapping("/login")
    @ResponseBody
    public String login(
            @RequestParam(value = "name", required = false) String name,
            @RequestParam(value = "password", required = false) String password
    ) {
        return "name:" + name + " password:" + password;
    }
}

6、src/main/java/com/mouday/quartz/SimpleJob.java

package com.mouday.quartz;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component("simpleJob")
public class SimpleJob {
    public void sayHello(){
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("SimpleJob "+ dateFormat.format(new Date()) );
    }
}

7、src/main/java/com/mouday/quartz/ComplexJob.java

package com.mouday.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ComplexJob extends QuartzJobBean {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("ComplexJob name: " + this.name + " " + dateFormat.format(new Date()));
    }
}

总结

  1. Timer 优缺点
  2. Quartz 三大要素
  3. Quartz&Spring 融合
相关文章
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
68 9
|
22天前
|
SQL Java 索引
java小工具util系列2:字符串工具
java小工具util系列2:字符串工具
137 83
|
19天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
22天前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
53 26
|
23天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
48 24
|
22天前
|
数据采集 存储 监控
Java爬虫:数据采集的强大工具
在数据驱动的时代,Java爬虫技术凭借其强大的功能和灵活性,成为企业获取市场信息、用户行为及竞争情报的关键工具。本文详细介绍了Java爬虫的工作原理、应用场景、构建方法及其重要性,强调了在合法合规的前提下,如何有效利用Java爬虫技术为企业决策提供支持。
|
1月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
44 5
|
1月前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
76 5
|
2月前
|
Web App开发 Java
使用java操作浏览器的工具selenium-java和webdriver下载地址
【10月更文挑战第12天】Selenium-java依赖包用于自动化Web测试,版本为3.141.59。ChromeDriver和EdgeDriver分别用于控制Chrome和Edge浏览器,需确保版本与浏览器匹配。示例代码展示了如何使用Selenium-java模拟登录CSDN,包括设置驱动路径、添加Cookies和获取页面源码。
131 6
|
1月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
45 0
下一篇
DataWorks