工作目录第一次备份

master
RENCHAO 1 year ago
commit eb9908d993

@ -0,0 +1,67 @@
<?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>com.renchao</groupId>
<artifactId>Drools</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 规则引擎 -->
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.6.0.Final</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,11 @@
package com.renchao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@ -0,0 +1,31 @@
package com.renchao.bean;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
public class Order {
/**
*
*/
private int price;
/**
*
*/
private User user;
/**
*
*/
private int score;
/**
*
*/
private Date bookingDate;
}

@ -0,0 +1,9 @@
package com.renchao.bean;
import lombok.Data;
@Data
public class User {
private String name;
private Integer level;
}

@ -0,0 +1,67 @@
package com.renchao.config;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
/**
* <p> </p>
*/
@Configuration
public class DroolsAutoConfiguration {
private static final String RULES_PATH = "rules/";
private KieServices getKieServices() {
return KieServices.Factory.get();
}
@Bean
@ConditionalOnMissingBean(KieFileSystem.class)
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
}
private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
}
@Bean
@ConditionalOnMissingBean(KieContainer.class)
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository();
kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
return kieContainer;
}
@Bean
@ConditionalOnMissingBean(KieBase.class)
public KieBase kieBase() throws IOException {
return kieContainer().getKieBase();
}
}

@ -0,0 +1,47 @@
package rules
import com.renchao.bean.Order
rule "zero"
no-loop true
lock-on-active true
salience 1
when
$s : Order(price <= 100)
then
$s.setScore(0);
update($s);
end
rule "add100"
no-loop true
lock-on-active true
salience 1
when
$s : Order(price > 100 && price <= 500)
then
$s.setScore(100);
update($s);
end
rule "add500"
no-loop true
lock-on-active true
salience 1
when
$s : Order(price > 500 && price <= 1000)
then
$s.setScore(500);
update($s);
end
rule "add1000"
no-loop true
lock-on-active true
salience 1
when
$s : Order(price > 1000)
then
$s.setScore(1000);
update($s);
end

@ -0,0 +1,96 @@
package com.renchao;
import com.renchao.bean.Order;
import com.renchao.bean.User;
import org.junit.jupiter.api.Test;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
*
* :
* 100,
* 100-500 100
* 500-1000 500
* 1000 1000
*/
@SpringBootTest
public class DroolsOrderTests {
@Resource
private KieContainer kieContainer;
@Test
public void droolsOrderTest() throws Exception {
KieSession kieSession = kieContainer.newKieSession();
List<Order> orderList = getInitData();
for (Order order: orderList) {
// 1-规则引擎处理逻辑
kieSession.insert(order);
kieSession.fireAllRules();
// 2-执行完规则后, 执行相关的逻辑
addScore(order);
}
kieSession.dispose();
}
private static void addScore(Order o){
System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
}
private static List<Order> getInitData() throws Exception {
List<Order> orderList = new ArrayList<>();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
{
Order order = new Order();
order.setPrice(80);
order.setBookingDate(df.parse("2015-07-01"));
User user = new User();
user.setLevel(1);
user.setName("Name1");
order.setUser(user);
order.setScore(111);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(200);
order.setBookingDate(df.parse("2015-07-02"));
User user = new User();
user.setLevel(2);
user.setName("Name2");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(800);
order.setBookingDate(df.parse("2015-07-03"));
User user = new User();
user.setLevel(3);
user.setName("Name3");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(1500);
order.setBookingDate(df.parse("2015-07-04"));
User user = new User();
user.setLevel(4);
user.setName("Name4");
order.setUser(user);
orderList.add(order);
}
return orderList;
}
}

@ -0,0 +1,136 @@
<?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>MyMaven</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- EasyExcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
<!--常用工具库-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.26</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>compile</scope>
</dependency>
<!-- drools规则引擎 -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.6.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.14</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.poi</groupId>-->
<!-- <artifactId>poi</artifactId>-->
<!-- <version>4.1.1</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.poi</groupId>-->
<!-- <artifactId>poi-ooxml</artifactId>-->
<!-- <version>4.1.1</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.36</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.36</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,42 @@
package com.renchao.chemical;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class DangerChemicalInfo {
@ExcelProperty(value = "序号")
private String number;
@ExcelProperty(value = "日期")
private String date;
@ExcelProperty(value = "样品名称及型号")
private String nameAndModel;
@ExcelProperty(value = "进口国别/地区")
private String country;
@ExcelProperty(value = "进口收货人/消费使用单位")
private String receiver;
@ExcelProperty(value = "生产商/发货人")
private String consignor;
@ExcelProperty(value = "成分/组分")
private String composition;
@ExcelProperty(value = "危险特性")
private String hazardousProperties;
@ExcelProperty(value = "危险类别")
private String hazardCategory;
@ExcelProperty(value = "联合国编号")
private String unNumber;
@ExcelProperty(value = "建议包装类别")
private String packingCategory;
}

@ -0,0 +1,113 @@
package com.renchao.chemical;
import com.alibaba.excel.EasyExcel;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DataProcessing {
/**
*
*/
private static final Pattern HAZARD_CATEGORY_PATTERN1 = Pattern.compile("类别[:]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?)([(]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?))[)])?)");
private static final Pattern HAZARD_CATEGORY_PATTERN2 = Pattern.compile("(\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?)([(]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?))[)])?");
/**
*
*/
private static final Pattern UN_NUMBER_PATTERN = Pattern.compile("([Uu][Nn])?(\\d{4})");
/**
*
*/
private static final Pattern PACKING_CATEGORY_PATTERN = Pattern.compile("[,:;/](I{1,3}|([ⅠⅡⅢ]))|\\d{4}[,:;/]([123])");
public static void main(String[] args) {
String filePath = "C:/Users/RENCHAO/Desktop/gggg.xlsx";
List<DangerChemicalInfo> list = EasyExcel.read(filePath).head(DangerChemicalInfo.class).sheet("第二次Mysql插入数据").doReadSync();
for (DangerChemicalInfo info : list) {
String properties = info.getHazardousProperties();
if (properties == null) {
continue;
}
info.setHazardCategory(processHazardCategory(properties));
info.setUnNumber(processUnNumber(properties));
info.setPackingCategory(processPackingCategory(properties));
}
EasyExcel.write("C:/Users/RENCHAO/Desktop/资料/bbr.xlsx", DangerChemicalInfo.class).sheet("Sheet1").doWrite(list);
System.out.println("完成!!!!");
}
/**
*
*/
private static String processHazardCategory(String properties) {
String category = processHazardCategory(properties, HAZARD_CATEGORY_PATTERN1);
if (category != null) {
return category;
}
return processHazardCategory(properties, HAZARD_CATEGORY_PATTERN2);
}
private static String processHazardCategory(String properties, Pattern pattern) {
int index = 0;
if (pattern == HAZARD_CATEGORY_PATTERN1) {
index = 1;
}
Matcher matcher = pattern.matcher(properties);
String category;
if (matcher.find()) {
// 后面是否又括号
String brackets = matcher.group(index + 6);
if (brackets == null) {
category = matcher.group(index);
} else {
category = matcher.group(index + 3) + "+" + brackets;
}
return category.replace("/", "+");
}
return null;
}
/**
*
*/
private static String processUnNumber(String properties) {
Matcher matcher = UN_NUMBER_PATTERN.matcher(properties);
if (matcher.find()) {
return matcher.group(2);
}
return null;
}
/**
*
*/
private static String processPackingCategory(String properties) {
Matcher matcher = PACKING_CATEGORY_PATTERN.matcher(properties);
if (matcher.find()) {
String category;
if (matcher.group(3) != null) {
category = matcher.group(3);
} else {
category = matcher.group(1);
}
if ("III".equals(category) || "3".equals(category)) {
return "Ⅲ";
}
if ("II".equals(category) || "2".equals(category)) {
return "Ⅱ";
}
if ("I".equals(category) || "1".equals(category)) {
return "";
}
return category;
}
return null;
}
}

@ -0,0 +1,106 @@
package com.renchao.drools;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DroolsTest {
KieContainer kieContainer;
public DroolsTest() {
KieServices kieServices = KieServices.Factory.get();
// 获取Kie容器对象默认容器对象
this.kieContainer = kieServices.newKieClasspathContainer();
kieContainer.newKieSession().dispose();
}
@Test
public void test02() {
KieSession kieSession1 = kieContainer.newKieSession();
List<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
kieSession1.insert(list);
System.out.println("第一个====");
kieSession1.fireAllRules();
// kieSession1.fireAllRules(match -> "book_discount_8".equals(match.getRule().getName()));
System.out.println("第二个====");
kieSession1.insert(new ArrayList<>());
kieSession1.fireAllRules();
//
// kieSession1.fireAllRules();
}
@Test
public void test03() {
KieSession kieSession = kieContainer.newKieSession();
Order order = new Order();
// order.setStringList(null);
kieSession.insert(order);
kieSession.fireAllRules();
}
@Test
public void test01() {
extracted();
extracted();
extracted();
extracted();
}
private void extracted() {
long l = System.currentTimeMillis();
KieSession kieSession = kieContainer.newKieSession();
Integer[] integers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Set<Integer> set = new HashSet<>();
List<Integer> list = new ArrayList<>();
kieSession.insert(set);
kieSession.insert(list);
for (Integer integer : integers) {
kieSession.insert(integer);
kieSession.fireAllRules(match -> "book_discount_7".equals(match.getRule().getName()));
kieSession.fireAllRules();
}
kieSession.dispose();
System.out.println(set);
System.out.println(list);
System.out.println("耗时:" + (System.currentTimeMillis() - l));
}
@Test
public void test() {
KieSession kieSession = kieContainer.newKieSession();
Order order = new Order();
order.setOriginalPrice(60d);
// 将order对象插入工作内存
kieSession.insert(order);
String str = "我试一试的。。。。。";
kieSession.insert(str);
System.out.println("匹配规则前优惠后价格:" + order.getRealPrice());
// 匹配对象
// 激活规则由drools框架自动进行规则匹配。若匹配成功则执行
kieSession.fireAllRules();
// 关闭会话
kieSession.dispose();
System.out.println("优惠前价格:" + order.getOriginalPrice() + "\n优惠后价格" + order.getRealPrice());
}
}

@ -0,0 +1,16 @@
package com.renchao.drools;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
@Data
public class Order {
private Double originalPrice; // 订单原始价格,即优惠前的价格
private Double realPrice; // 订单真实价格,即优惠后的价格
private List<String> stringList = new ArrayList<>();
}

@ -0,0 +1,104 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
* Copyright (c) 2014, Oracle America, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Oracle nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
public class JMHSample_01_HelloWorld {
/**
* This is our first benchmark method.
*
* JMH works as follows: users annotate the methods with @Benchmark, and
* then JMH produces the generated code to run this particular benchmark as
* reliably as possible. In general one might think about @Benchmark methods
* as the benchmark "payload", the things we want to measure. The
* surrounding infrastructure is provided by the harness itself.
*
* Read the Javadoc for @Benchmark annotation for complete semantics and
* restrictions. At this point we only note that the methods names are
* non-essential, and it only matters that the methods are marked with
* @Benchmark. You can have multiple benchmark methods within the same
* class.
*
* Note: if the benchmark method never finishes, then JMH run never finishes
* as well. If you throw an exception from the method body the JMH run ends
* abruptly for this benchmark and JMH will run the next benchmark down the
* list.
*
* Although this benchmark measures "nothing" it is a good showcase for the
* overheads the infrastructure bear on the code you measure in the method.
* There are no magical infrastructures which incur no overhead, and it is
* important to know what are the infra overheads you are dealing with. You
* might find this thought unfolded in future examples by having the
* "baseline" measurements to compare against.
*/
@Benchmark
public void wellHelloThere() {
// this method was intentionally left blank.
}
/**
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You are expected to see the run with large number of iterations, and
* very large throughput numbers. You can see that as the estimate of the
* harness overheads per method call. In most of our measurements, it is
* down to several cycles per call.
*
* a) Via command-line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_01
*
* JMH generates self-contained JARs, bundling JMH together with it.
* The runtime options for the JMH are available with "-h":
* $ java -jar target/benchmarks.jar -h
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_01_HelloWorld.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,183 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* -
*
* @see Mode
*
* @author childe
* @date 2018/9/19 11:29
**/
public class JMHSample_02_BenchmarkModes {
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(JMHSample_02_BenchmarkModes.class.getSimpleName())
.exclude(JMHSample_02_BenchmarkModes.class.getSimpleName() + ".measureAll")
.exclude(JMHSample_02_BenchmarkModes.class.getSimpleName() + ".measureMultiple")
.output("JMHSample_02_BenchmarkModes_result.sampleLog")
.forks(1)
.build();
new Runner(options).run();
}
/*
* JMH generates lots of synthetic code for the benchmarks for you during
* the benchmark compilation. JMH can measure the benchmark methods in lots
* of modes. Users may select the default benchmark mode with a special
* annotation, or select/override the mode via the runtime options.
*
* With this scenario, we start to measure something useful. Note that our
* payload code potentially throws exceptions, and we can just declare them
* to be thrown. If the code throws the actual exception, the benchmark
* execution will stop with an error.
*
* When you are puzzled with some particular behavior, it usually helps to
* look into the generated code. You might see the code is doing not
* something you intend it to do. Good experiments always follow up on the
* experimental setup, and cross-checking the generated code is an important
* part of that follow up.
*
* The generated code for this particular sample is somewhere at
* target/generated-sources/annotations/.../JMHSample_02_BenchmarkModes.java
*/
/**
* <p>Throughput: ops/time</p>
*
* <p>{@link Benchmark}线
* </p>
*
* Mode.Throughput, as stated in its Javadoc, measures the raw throughput by
* continuously calling the benchmark method in a time-bound iteration, and
* counting how many times we executed the method.
*
* We are using the special annotation to select the units to measure in,
* although you can use the default.
*/
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public static void measureThroughput() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
/*
* Mode.AverageTime measures the average execution time, and it does it
* in the way similar to Mode.Throughput.
*
* Some might say it is the reciprocal throughput, and it really is.
* There are workloads where measuring times is more convenient though.
*/
/**
* <p>Average time: time/op</p>
*
* <p>{@link Benchmark}线{@link Mode#Throughput}
* </p>
*/
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void measureAverageTime() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
/*
* Mode.SampleTime samples the execution time. With this mode, we are
* still running the method in a time-bound iteration, but instead of
* measuring the total time, we measure the time spent in *some* of
* the benchmark method calls.
*
* This allows us to infer the distributions, percentiles, etc.
*
* JMH also tries to auto-adjust sampling frequency: if the method
* is long enough, you will end up capturing all the samples.
*/
/**
* <p>Sample time: Sampling time</p>
*
* <p>This mode automatically adjusts the sampling
* frequency, but may omit some pauses which missed the sampling measurement. </p>
* <p>
* {@link Benchmark}
*
*
* </p>
*/
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void measureSampleTime() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
/*
* Mode.SingleShotTime measures the single method invocation time. As the Javadoc
* suggests, we do only the single benchmark method invocation. The iteration
* time is meaningless in this mode: as soon as benchmark method stops, the
* iteration is over.
*
* This mode is useful to do cold startup tests, when you specifically
* do not want to call the benchmark method continuously.
*/
/**
*
* <p>Single shot time: </p>
* <p>
* {@link Benchmark}
* "冷"
* {@link Benchmark}
* </p>
* :
* <ul>
* <li>/</li>
* <li>{@link Mode#SampleTime} </li>
* </ul>
*/
@Benchmark
@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void measureSingleShotTime() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
/*
* We can also ask for multiple benchmark modes at once. All the tests
* above can be replaced with just a single test like this:
*/
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime})
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void measureMultiple() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
/**
* Meta-mode: all the benchmark modes.
* This is mostly useful for internal JMH testing.
*/
@Benchmark
@BenchmarkMode(Mode.All)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void measureAll() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}
}

@ -0,0 +1,85 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
*
* @see Scope
*
* @author childe
* @date 2018/9/20 16:02
**/
public class JMHSample_03_States {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_03_States.class.getSimpleName())
.output("JMHSample_03_States_result.sampleLog")
.threads(4)
.forks(1)
.build();
new Runner(opt).run();
}
/*
* JHM
* state-bearing
*
* @State
* <b>使</b>
*
* 线访
* 线ThreadLocals
*
*/
@State(Scope.Benchmark)
public static class BenchmarkState {
{
System.out.println("swwwws");
}
volatile double x = Math.PI;
}
@State(Scope.Thread)
public static class ThreadState {
{
System.out.println("ss");
}
volatile double x = Math.PI;
}
/*
* BenchmarkJHM
*
* 使线
*/
@Benchmark
public void measureUnshared(ThreadState state) {
// All benchmark threads will call in this method.
//
// However, since ThreadState is the Scope.Thread, each thread
// will have it's own copy of the state, and this benchmark
// will measure unshared case.
state.x++;
}
@Benchmark
public void measureShared(BenchmarkState state) {
// All benchmark threads will call in this method.
//
// Since BenchmarkState is the Scope.Benchmark, all threads
// will share the state instance, and we will end up measuring
// shared case.
state.x++;
}
}

@ -0,0 +1,37 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
*
* benchmark@State
* Java
*
* @author childe
* @date 2018/9/20 17:08
**/
@State(Scope.Thread)
public class JMHSample_04_DefaultState {
private double x = Math.PI;
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(JMHSample_04_DefaultState.class.getSimpleName())
.output("JMHSample_04_DefaultState_result.sampleLog")
.threads(1)
.forks(1)
.build();
new Runner(options).run();
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
public void measureDefaultState() {
x++;
}
}

@ -0,0 +1,113 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
* @see Level
* @see Setup
* @see TearDown
*
* @author childe
* @date 2018/10/8 11:23
**/
@State(Scope.Thread)
public class JMHSample_05_StateFixtures {
private double x;
/*
* Since @State objects are kept around during the lifetime of the
* benchmark, it helps to have the methods which do state housekeeping.
* These are usual fixture methods, you are probably familiar with them from
* JUnit and TestNG.
*
* Fixture methods make sense only on @State objects, and JMH will fail to
* compile the test otherwise.
*
* As with the State, fixture methods are only called by those benchmark
* threads which are using the state. That means you can operate in the
* thread-local context, and (not) use synchronization as if you are
* executing in the context of benchmark thread.
*
* Note: fixture methods can also work with static fields, although the
* semantics of these operations fall back out of State scope, and obey
* usual Java rules (i.e. one static field per class).
*
* @Statebenchmark使
* fixtureJUnitTestNG
* @see org.openjdk.jmh.annotations.Level
*
* fixture@StateJHM
*
* Statefixture使statebenchmark线 线
* 使benchmark线
*
* fixture使State退Java
*/
/*
* Level@Benchmark
* Ok, let's prepare our benchmark:
*/
@Setup
public void prepare() {
x = Math.PI;
}
/*
* Level@TearDown
* And, check the benchmark went fine afterwards:
*/
@TearDown
public void check() {
assert x > Math.PI : "Nothing changed?";
}
/*
* This method obviously does the right thing, incrementing the field x
* in the benchmark state. check() will never fail this way, because
* we are always guaranteed to have at least one benchmark call.
*/
@Benchmark
public void measureRight() {
x++;
}
/*
* This method, however, will fail the check(), because we deliberately
* have the "typo", and increment only the local variable. This should
* not pass the check, and JMH will fail the run.
*/
@Benchmark
public void measureWrong() {
double x = 0;
x++;
}
/*
* java -ea //启动断言
* java -ea:pkname... //在包pkname及其子包下起用断言
* java -ea:pkname.classname //对类 pkname.classname启用断言
*
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_05_StateFixtures.class.getSimpleName())
.forks(1)
.jvmArgs("-ea")
.output("JMHSample_05_StateFixtures.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,79 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
* @see Level
* @see Setup
* @see TearDown
*
* @author childe
* @date 2018/10/8 15:36
**/
@State(Scope.Thread)
public class JMHSample_06_FixtureLevel {
private double x;
/*
* Fixture methods have different levels to control when they should be run.
* There are at least three Levels available to the user. These are, from
* top to bottom:
*
* Level.Trial: before or after the entire benchmark run (the sequence of iterations)
* Level.Iteration: before or after the benchmark iteration (the sequence of invocations)
* Level.Invocation; before or after the benchmark method invocation (WARNING: read the Javadoc before using)
*
* Time spent in fixture methods does not count into the performance
* metrics, so you can use this to do some heavy-lifting.
*
* fixture
* 使
*
* Level.Trial@Benchmark
* Level.Iteration
* Level.Invocation @see org.openjdk.jmh.annotations.Level
*
* fixture
*/
@TearDown(Level.Iteration)
public void check() {
assert x > Math.PI : "Nothing changed?";
}
@Benchmark
public void measureRight() {
x++;
}
@Benchmark
public void measureWrong() {
double x = 0;
x++;
}
/*
* java -ea //启动断言
* java -ea:pkname... //在包pkname及其子包下起用断言
* java -ea:pkname.classname //对类 pkname.classname启用断言
*
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_06_FixtureLevel.class.getSimpleName())
.forks(1)
.jvmArgs("-ea")
// switch to "true" to fail the complete run
.shouldFailOnError(false)
.output("JMHSample_06_FixtureLevel.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,137 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.*;
/**
* Fixtures have different Levels to control when they are about to run.
* Level.Invocation is useful sometimes to do some per-invocation work
* which should not count as payload (e.g. sleep for some time to emulate
* think time)
*
* fixture
* Level.Invocation
*
* @author childe
* @date 2018/10/8 17:13
**/
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class JMHSample_07_FixtureLevelInvocation {
/*
* Fixtures have different Levels to control when they are about to run.
* Level.Invocation is useful sometimes to do some per-invocation work,
* which should not count as payload. PLEASE NOTE the timestamping and
* synchronization for Level.Invocation helpers might significantly offset
* the measurement, use with care. See Level.Invocation javadoc for further
* discussion.
*
* fixture
* Level.Invocation
* Level.Invocation使
*
* Consider this sample:
*
*/
/*
* This state handles the executor.
* Note we create and shutdown executor with Level.Trial, so
* it is kept around the same across all iterations.
*/
@State(Scope.Benchmark)
public static class NormalState {
ExecutorService service;
@Setup(Level.Trial)
public void up() {
System.out.println("up");
service = Executors.newCachedThreadPool();
}
@TearDown(Level.Trial)
public void down() {
service.shutdown();
}
}
/*
* This is the *extension* of the basic state, which also
* has the Level.Invocation fixture method, sleeping for some time.
*
* @State
*/
public static class LaggingState extends NormalState {
static final int SLEEP_TIME = Integer.getInteger("sleepTime", 10);
@Setup(Level.Invocation)
public void lag() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
}
}
/*
* This allows us to formulate the task: measure the task turnaround in
* "hot" mode when we are not sleeping between the submits, and "cold" mode,
* when we are sleeping.
*/
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public double measureHot(NormalState e, final Scratch s) throws ExecutionException, InterruptedException {
return e.service.submit(new Task(s)).get();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public double measureCold(LaggingState e, final Scratch s) throws ExecutionException, InterruptedException {
return e.service.submit(new Task(s)).get();
}
/*
* This is our scratch state which will handle the work.
*/
@State(Scope.Thread)
public static class Scratch {
private double p;
private double doWork() {
p = Math.log(p);
return p;
}
}
public static class Task implements Callable<Double> {
private Scratch s;
private Task(Scratch s) {
this.s = s;
}
@Override
public Double call() {
return s.doWork();
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_07_FixtureLevelInvocation.class.getSimpleName())
.forks(1)
.output("JMHSample_07_FixtureLevelInvocation.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,74 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* Dead-Code Elimination (DCE)
*
*
* @author childe
* @date 2018/10/9 11:18
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_08_DeadCode {
/*
* The downfall of many benchmarks is Dead-Code Elimination (DCE): compilers
* are smart enough to deduce some computations are redundant and eliminate
* them completely. If the eliminated part was our benchmarked code, we are
* in trouble.
*
* Fortunately, JMH provides the essential infrastructure to fight this
* where appropriate: returning the result of the computation will ask JMH
* to deal with the result to limit dead-code elimination (returned results
* are implicitly consumed by Blackholes, see JMHSample_09_Blackholes).
*
* DCE
*
*
*
* JMH便JMH
* Blackholes JMHSample_09_Blackholes
*
*/
private double x = Math.PI;
@Benchmark
public void baseline() {
// do nothing, this is a baseline
// 基准线
}
@Benchmark
public void measureWrong() {
// This is wrong: result is not used and the entire computation is optimized away.
// 这是错误的:结果没有被使用,整个计算将会被编译器优化。
Math.log(x);
}
@Benchmark
public double measureRight() {
// This is correct: the result is being used.
return Math.log(x);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_08_DeadCode.class.getSimpleName())
.output("JMHSample_08_DeadCode.sampleLog")
.forks(1)
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,101 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author childe
* @date 2018/10/9 11:44
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class JMHSample_09_Blackholes {
/*
* Should your benchmark require returning multiple results, you have to
* consider two options (detailed below).
*
* NOTE: If you are only producing a single result, it is more readable to
* use the implicit return, as in JMHSample_08_DeadCode. Do not make your benchmark
* code less readable with explicit Blackholes!
*
*
* 使returnJMHSample_08_DeadCode
* 使Blackholes
*/
double x1 = Math.PI;
double x2 = Math.PI * 2;
/*
* Baseline measurement: how much single Math.sampleLog costs.
*/
@Benchmark
public double baseline() {
return Math.log(x1);
}
/*
* While the Math.sampleLog(x2) computation is intact, Math.sampleLog(x1)
* is redundant and optimized out.
*/
@Benchmark
public double measureWrong() {
Math.log(x1);
return Math.log(x2);
}
/*
* This demonstrates Option A:
*
* Merge multiple results into one and return it.
* This is OK when is computation is relatively heavyweight, and merging
* the results does not offset the results much.
*
* A
*
*
*/
@Benchmark
public double measureRight_1() {
return Math.log(x1) + Math.log(x2);
}
/*
* This demonstrates Option B:
*
* Use explicit Blackhole objects, and sink the values there.
* (Background: Blackhole is just another @State object, bundled with JMH).
*
* B
* 使Blackhole
* Blackhole@StateJMH
*/
@Benchmark
public void measureRight_2(Blackhole bh) {
bh.consume(Math.log(x1));
bh.consume(Math.log(x2));
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_09_Blackholes.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,84 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* DCEconstant-folding
*
* @author childe
* @date 2018/10/9 14:27
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_10_ConstantFold {
/*
* The flip side of dead-code elimination is constant-folding.
*
* If JVM realizes the result of the computation is the same no matter what,
* it can cleverly optimize it. In our case, that means we can move the
* computation outside of the internal JMH loop.
*
* This can be prevented by always reading the inputs from non-final
* instance fields of @State objects, computing the result based on those
* values, and follow the rules to prevent DCE.
*
*
* JVM便
* JMH
*
* @Statenon-finalDCE
*/
// IDEs will say "Oh, you can convert this field to local variable". Don't. Trust. Them.
// (While this is normally fine advice, it does not work in the context of measuring correctly.)
// 哈哈,竟然言中
private double x = Math.PI;
// IDEs will probably also say "Look, it could be final". Don't. Trust. Them. Either.
// (While this is normally fine advice, it does not work in the context of measuring correctly.)
// 哈哈,原因说错了
private final double wrongX = Math.PI;
@Benchmark
public double baseline() {
// simply return the value, this is a baseline
return Math.PI;
}
@Benchmark
public double measureWrong_1() {
// This is wrong: the source is predictable, and computation is foldable.
return Math.log(Math.PI);
}
@Benchmark
public double measureWrong_2() {
// This is wrong: the source is predictable, and computation is foldable.
return Math.log(wrongX);
}
@Benchmark
public double measureRight() {
// This is correct: the source is not predictable.
return Math.log(x);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_10_ConstantFold.class.getSimpleName())
.forks(1)
.output("JMHSample_10_ConstantFold.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,134 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author childe
* @date 2018/10/9 15:51
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_11_Loops {
/*
* It would be tempting for users to do loops within the benchmarked method.
* (This is the bad thing Caliper taught everyone). These tests explain why
* this is a bad idea.
*
* Looping is done in the hope of minimizing the overhead of calling the
* test method, by doing the operations inside the loop instead of inside
* the method call. Don't buy this argument; you will see there is more
* magic happening when we allow optimizers to merge the loop iterations.
*
* Caliper
*
*
* ;
*/
/*
* Suppose we want to measure how much it takes to sum two integers:
*/
int x = 1;
int y = 2;
/*
* This is what you do with JMH.
*/
@Benchmark
public int measureRight() {
return (x + y);
}
/*
* The following tests emulate the naive looping.
* This is the Caliper-style benchmark.
*
* Caliper
*/
private int reps(int reps) {
int s = 0;
for (int i = 0; i < reps; i++) {
s += (x + y);
}
return s;
}
/*
* We would like to measure this with different repetitions count.
* Special annotation is used to get the individual operation cost.
*/
@Benchmark
@OperationsPerInvocation(1)
public int measureWrong_1() {
return reps(1);
}
@Benchmark
@OperationsPerInvocation(10)
public int measureWrong_10() {
return reps(10);
}
@Benchmark
@OperationsPerInvocation(100)
public int measureWrong_100() {
return reps(100);
}
@Benchmark
@OperationsPerInvocation(1000)
public int measureWrong_1000() {
return reps(1000);
}
@Benchmark
@OperationsPerInvocation(10000)
public int measureWrong_10000() {
return reps(10000);
}
@Benchmark
@OperationsPerInvocation(100000)
public int measureWrong_100000() {
return reps(100000);
}
/*
* You might notice the larger the repetitions count, the lower the "perceived"
* cost of the operation being measured. Up to the point we do each addition with 1/20 ns,
* well beyond what hardware can actually do.
*
* This happens because the loop is heavily unrolled/pipelined, and the operation
* to be measured is hoisted from the loop. Morale: don't overuse loops, rely on JMH
* to get the measurement right.
*
* 1/20 ns
*
* unrolled/pipelined使JMH
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_11_Loops.class.getSimpleName())
.forks(1)
.output("JMHSample_11_Loops.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,162 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* Use non-forked runs only for debugging purposes, not for actual performance runs
* 使non-forked
*
* @author childe
* @date 2018/10/9 17:17
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_12_Forking {
/*
* JVMs are notoriously good at profile-guided optimizations. This is bad
* for benchmarks, because different tests can mix their profiles together,
* and then render the "uniformly bad" code for every test. Forking (running
* in a separate process) each test can help to evade this issue.
*
* JMH will fork the tests by default.
*
* JVMprofile-guidedprofiles
* "uniformly bad"forking
*
* JMHforktest
*/
/*
* Suppose we have this simple counter interface, and two implementations.
* Even though those are semantically the same, from the JVM standpoint,
* those are distinct classes.
*
*
* 使JVM
*/
public interface Counter {
int inc();
}
public class Counter1 implements Counter {
private int x;
@Override
public int inc() {
return x++;
}
}
public class Counter2 implements Counter {
private int x;
@Override
public int inc() {
return x++;
}
}
/*
* And this is how we measure it.
* Note this is susceptible for same issue with loops we mention in previous examples.
*/
public int measure(Counter c) {
int s = 0;
for (int i = 0; i < 10; i++) {
s += c.inc();
}
return s;
}
/*
* These are two counters.
*/
Counter c1 = new Counter1();
Counter c2 = new Counter2();
/*
* We first measure the Counter1 alone...
* Fork(0) helps to run in the same JVM.
*/
@Benchmark
@Fork(0)
public int measure_1_c1() {
return measure(c1);
}
/*
* Then Counter2...
*/
@Benchmark
@Fork(0)
public int measure_2_c2() {
return measure(c2);
}
/*
* Then Counter1 again...
*/
@Benchmark
@Fork(0)
public int measure_3_c1_again() {
return measure(c1);
}
/*
* These two tests have explicit @Fork annotation.
* JMH takes this annotation as the request to run the test in the forked JVM.
* It's even simpler to force this behavior for all the tests via the command
* line option "-f". The forking is default, but we still use the annotation
* for the consistency.
*
* This is the test for Counter1.
*/
@Benchmark
@Fork(1)
public int measure_4_forked_c1() {
return measure(c1);
}
/*
* ...and this is the test for Counter2.
*/
@Benchmark
@Fork(1)
public int measure_5_forked_c2() {
return measure(c2);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note that C1 is faster, C2 is slower, but the C1 is slow again! This is because
* the profiles for C1 and C2 had merged together.
*
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_12_Forking.class.getSimpleName())
.output("JMHSample_12_Forking.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,118 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* run-to-run variance
*
*
* @author childe
* @date 2018/10/10 09:16
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class JMHSample_13_RunToRun {
/*
* Forking also allows to estimate run-to-run variance.
*
* JVMs are complex systems, and the non-determinism is inherent for them.
* This requires us to always account the run-to-run variance as the one
* of the effects in our experiments.
*
* Luckily, forking aggregates the results across several JVM launches.
*
* fork
* JVM
*
*
* forkJVM
*/
/*
* In order to introduce readily measurable run-to-run variance, we build
* the workload which performance differs from run to run. Note that many workloads
* will have the similar behavior, but we do that artificially to make a point.
*
*
*
*/
@State(Scope.Thread)
public static class SleepyState {
public long sleepTime;
@Setup
public void setup() {
// 每次fork都会执行fork相当于重复多次某个被标记@Benchmark注解的方法但它会合并结果。
sleepTime = (long) (Math.random() * 1000);
}
}
/*
* Now, we will run this different number of times.
*/
@Benchmark
@Fork(1)
public void baseline(SleepyState s) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(s.sleepTime);
}
@Benchmark
@Fork(5)
public void fork_1(SleepyState s) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(s.sleepTime);
}
@Benchmark
@Fork(20)
public void fork_2(SleepyState s) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(s.sleepTime);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note the baseline is random within [0..1000] msec; and both forked runs
* are estimating the average 500 msec with some confidence.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_13 -wi 0 -i 3
* (we requested no warmup, 3 measurement iterations; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_13_RunToRun.class.getSimpleName())
.warmupIterations(0)
.measurementIterations(3)
.output("JMHSample_13_RunToRun.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,122 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Group;
import org.openjdk.jmh.annotations.GroupThreads;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
*
* /
*
* @author childe
* @date 2018/10/10 10:40
**/
@State(Scope.Group)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_15_Asymmetric {
/*
* So far all the tests were symmetric: the same code was executed in all the threads.
* At times, you need the asymmetric test. JMH provides this with the notion of @Group,
* which can bind several methods together, and all the threads are distributed among
* the test methods.
*
* Each execution group contains of one or more threads. Each thread within a particular
* execution group executes one of @Group-annotated @Benchmark methods. Multiple execution
* groups may participate in the run. The total thread count in the run is rounded to the
* execution group size, which will only allow the full execution groups.
*
* Note that two state scopes: Scope.Benchmark and Scope.Thread are not covering all
* the use cases here -- you either share everything in the state, or share nothing.
* To break this, we have the middle ground Scope.Group, which marks the state to be
* shared within the execution group, but not among the execution groups.
*
* Putting this all together, the example below means:
* a) define the execution group "g", with 3 threads executing inc(), and 1 thread
* executing get(), 4 threads per group in total;
* b) if we run this test case with 4 threads, then we will have a single execution
* group. Generally, running with 4*N threads will create N execution groups, etc.;
* c) each execution group has one @State instance to share: that is, execution groups
* share the counter within the group, but not across the groups.
*
* 线
* JMH@Group线
*
* 线线@Group-annotated @Benchmark
* 线
*
* Scope.Benchmark Scope.Thread -- 西
* 使Scope.Group
*
*
* a)"g"3线inc()1线get()4线
* b)4线4*N线N
* c)@Statecounter
*/
private AtomicInteger counter;
@Setup
public void up() {
counter = new AtomicInteger();
}
@Benchmark
@Group("g")
@GroupThreads(3)
public int inc() {
return counter.incrementAndGet();
}
@Benchmark
@Group("g")
@GroupThreads(1)
public int get() {
return counter.get();
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You will have the distinct metrics for inc() and get() from this run.
*
* inc()get()
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_15 -f 1
* (we requested single fork; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_15_Asymmetric.class.getSimpleName())
.forks(1)
.output("JMHSample_15_Asymmetric.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,161 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* Method Inlining
* JVM @see http://www.importnew.com/2009.html
*
*
* From http://www.oracle.com/technetwork/java/whitepaper-135217.html#method:
*
* The frequency of virtual method invocations in the Java programming language is an important optimization bottleneck.
* Once the Java HotSpot adaptive optimizer has gathered information during execution about program hot spots,
* it not only compiles the hot spot into native code, but also performs extensive method inlining on that code.
*
* Inlining has important benefits.
* It dramatically reduces the dynamic frequency of method invocations, which saves the time needed to perform those method invocations.
* But even more importantly, inlining produces much larger blocks of code for the optimizer to work on.
* This creates a situation that significantly increases the effectiveness of traditional compiler optimizations,
* overcoming a major obstacle to increased Java programming language performance.
*
* Inlining is synergistic with other code optimizations, because it makes them more effective.
* As the Java HotSpot compiler matures, the ability to operate on large, inlined blocks of code will open the door to a host of even more advanced optimizations in the future.
*
* Java
* Java HotSpot
*
*
*
*
* Java
*
* 使
* Java HotSpot
*
* @author childe
* @date 2018/10/10 14:16
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_16_CompilerControl {
/*
* We can use HotSpot-specific functionality to tell the compiler what
* do we want to do with particular methods. To demonstrate the effects,
* we end up with 3 methods in this sample.
*
* 使HotSpot
*
*/
/**
* These are our targets:
* - first method is prohibited from inlining
* - second method is forced to inline
* - third method is prohibited from compiling
*
* We might even place the annotations directly to the benchmarked
* methods, but this expresses the intent more clearly.
*
*
* -
* -
* -
*
*
*/
public void target_blank() {
// this method was intentionally left blank
// 方法故意留空
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public void target_dontInline() {
// this method was intentionally left blank
}
@CompilerControl(CompilerControl.Mode.INLINE)
public void target_inline() {
// this method was intentionally left blank
}
/**
* Exclude the method from the compilation.
*/
@CompilerControl(CompilerControl.Mode.EXCLUDE)
public void target_exclude() {
// this method was intentionally left blank
}
/*
* These method measures the calls performance.
*
*
*/
@Benchmark
public void baseline() {
// this method was intentionally left blank
}
@Benchmark
public void blank() {
target_blank();
}
@Benchmark
public void dontinline() {
target_dontInline();
}
@Benchmark
public void inline() {
target_inline();
}
@Benchmark
public void exclude() {
target_exclude();
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note the performance of the baseline, blank, and inline methods are the same.
* dontinline differs a bit, because we are making the proper call.
* exclude is severely slower, becase we are not compiling it at all.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_16 -wi 0 -i 3 -f 1
* (we requested no warmup iterations, 3 iterations, single fork; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_16_CompilerControl.class.getSimpleName())
.warmupIterations(0)
.measurementIterations(3)
.forks(1)
.output("JMHSample_16_CompilerControl.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,117 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/11 17:01
**/
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class JMHSample_17_SyncIterations {
/*
* This is the another thing that is enabled in JMH by default.
*
* Suppose we have this simple benchmark.
*/
private double src;
@Benchmark
public double test() {
double s = src;
for (int i = 0; i < 1000; i++) {
s = Math.sin(s);
}
return s;
}
/*
* It turns out if you run the benchmark with multiple threads,
* the way you start and stop the worker threads seriously affects
* performance.
*
* The natural way would be to park all the threads on some sort
* of barrier, and the let them go "at once". However, that does
* not work: there are no guarantees the worker threads will start
* at the same time, meaning other worker threads are working
* in better conditions, skewing the result.
*
* The better solution would be to introduce bogus iterations,
* ramp up the threads executing the iterations, and then atomically
* shift the system to measuring stuff. The same thing can be done
* during the rampdown. This sounds complicated, but JMH already
* handles that for you.
*
* 线benchmark线
*
* 线
* 线线
*
* 线
* JMH
*/
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You will need to oversubscribe the system to make this effect
* clearly visible; however, this effect can also be shown on the
* unsaturated systems.*
*
* 使;
*
* Note the performance of -si false version is more flaky, even
* though it is "better". This is the false improvement, granted by
* some of the threads executing in solo. The -si true version more stable
* and coherent.
*
* -si false使 -si true
*
* -si true is enabled by default.
*
* Say, $CPU is the number of CPUs on your machine.
*
* You can run this test with:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_17 \
* -w 1s -r 1s -f 1 -t ${CPU*16} -si {true|false}
* (we requested shorter warmup/measurement iterations, single fork,
* lots of threads, and changeable "synchronize iterations" option)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_17_SyncIterations.class.getSimpleName())
.warmupTime(TimeValue.seconds(1))
.measurementTime(TimeValue.seconds(1))
.threads(Runtime.getRuntime().availableProcessors()*16)
.forks(1)
// try to switch to "false", default is true
.syncIterations(false)
.output("JMHSample_17_SyncIterations_false.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,91 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Group;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Control;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* benchmark
* @see Control
* @author childe
* @date 2018/10/12 15:12
**/
@State(Scope.Group)
public class JMHSample_18_Control {
/*
* Sometimes you need the tap into the harness mind to get the info
* on the transition change. For this, we have the experimental state object,
* Control, which is updated by JMH as we go.
*
* 线ControlJMH
*
* WARNING: The API for Contro class is considered unstable, and can be changed without notice.
*/
/*
* In this example, we want to estimate the ping-pong speed for the simple
* AtomicBoolean. Unfortunately, doing that in naive manner will livelock
* one of the threads, because the executions of ping/pong are not paired
* perfectly. We need the escape hatch to terminate the loop if threads
* are about to leave the measurement.
*
* AtomicBooleanping / pong
* 线ping / pong
* 线"逃生舱口"
*/
public final AtomicBoolean flag = new AtomicBoolean();
@Benchmark
@Group("pingpong")
public void ping(Control cnt) {
// 业务在迭代时间未结束前,一直运行。
while (!cnt.stopMeasurement && !flag.compareAndSet(false, true)) {
// this body is intentionally left blank
}
}
@Benchmark
@Group("pingpong")
public void pong(Control cnt) {
while (!cnt.stopMeasurement && !flag.compareAndSet(true, false)) {
// this body is intentionally left blank
}
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_18 -t 2 -f 1
* (we requested 2 threads and single fork; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_18_Control.class.getSimpleName())
.threads(2)
.forks(1)
.output("JMHSample_18_Control.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,79 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author childe
* @date 2018/10/12 16:28
**/
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(1)
public class JMHSample_20_Annotations {
double x1 = Math.PI;
/*
* In addition to all the command line options usable at run time,
* we have the annotations which can provide the reasonable defaults
* for the some of the benchmarks. This is very useful when you are
* dealing with lots of benchmarks, and some of them require
* special treatment.
*
* Annotation can also be placed on class, to have the effect over
* all the benchmark methods in the same class. The rule is, the
* annotation in the closest scope takes the precedence: i.e.
* the method-based annotation overrides class-based annotation,
* etc.
*
*
*
*
* classclass
*
*
*
*/
@Benchmark
@Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
public double measure() {
return Math.log(x1);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note JMH honors the default annotation settings. You can always override
* the defaults via the command line or API.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_20
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_20_Annotations.class.getSimpleName())
.output("JMHSample_20_Annotations.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,139 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* Consume some amount of time tokens.
*
*
*
* CPUBlackHole.consumeCPU(tokens)
* TokenCPU(JIT/CPU)
*
* @author childe
* @date 2018/10/13 15:03
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_21_ConsumeCPU {
/*
* At times you require the test to burn some of the cycles doing nothing.
* In many cases, you *do* want to burn the cycles instead of waiting.
*
* For these occasions, we have the infrastructure support. Blackholes
* can not only consume the values, but also the time! Run this test
* to get familiar with this part of JMH.
*
* (Note we use static method because most of the use cases are deep
* within the testing code, and propagating blackholes is tedious).
*
*
*
*
*
* BlackholeJMH
*
* (使Blackhole)
*/
@Benchmark
public void consume_0000() {
Blackhole.consumeCPU(0);
}
@Benchmark
public void consume_0001() {
Blackhole.consumeCPU(1);
}
@Benchmark
public void consume_0002() {
Blackhole.consumeCPU(2);
}
@Benchmark
public void consume_0004() {
Blackhole.consumeCPU(4);
}
@Benchmark
public void consume_0008() {
Blackhole.consumeCPU(8);
}
@Benchmark
public void consume_0016() {
Blackhole.consumeCPU(16);
}
@Benchmark
public void consume_0032() {
Blackhole.consumeCPU(32);
}
@Benchmark
public void consume_0064() {
Blackhole.consumeCPU(64);
}
@Benchmark
public void consume_0128() {
Blackhole.consumeCPU(128);
}
@Benchmark
public void consume_0256() {
Blackhole.consumeCPU(256);
}
@Benchmark
public void consume_0512() {
Blackhole.consumeCPU(512);
}
@Benchmark
public void consume_1024() {
Blackhole.consumeCPU(1024);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note the single token is just a few cycles, and the more tokens
* you request, then more work is spent (almost linearly)
*
* token线
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_21 -f 1
* (we requested single fork; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_21_ConsumeCPU.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,104 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* AuxCounters
* CAVEAT: THIS IS AN EXPERIMENTAL API, it may be changed or removed in future without prior warning.
*
* @State
* @author childe
* @date 2018/10/16 15:20
**/
@OutputTimeUnit(TimeUnit.SECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
public class JMHSample_23_AuxCounters {
/*
* In some weird cases you need to get the separate throughput/time
* metrics for the benchmarked code depending on the outcome of the
* current code. Trying to accommodate the cases like this, JMH optionally
* provides the special annotation which treats @State objects
* as the object bearing user counters. See @AuxCounters javadoc for
* the limitations.
*/
@State(Scope.Thread)
@AuxCounters(AuxCounters.Type.OPERATIONS)
public static class OpCounters {
// These fields would be counted as metrics
public int case1;
public int case2;
// This accessor will also produce a metric
public int total() {
return case1 + case2;
}
}
@State(Scope.Thread)
// 计算“事件”,即工作量生命周期中的一次性事件。此计数器不会按时间标准化。
@AuxCounters(AuxCounters.Type.EVENTS)
public static class EventCounters {
// This field would be counted as metric
public int wows;
}
/*
* This code measures the "throughput" in two parts of the branch.
* The @AuxCounters state above holds the counters which we increment
* ourselves, and then let JMH to use their values in the performance
* calculations.
*/
@Benchmark
public void splitBranch(OpCounters counters) {
if (Math.random() < 0.1) {
counters.case1++;
} else {
counters.case2++;
}
}
@Benchmark
public void runSETI(EventCounters counters) {
float random = (float) Math.random();
float wowSignal = (float) Math.PI / 4;
if (random == wowSignal) {
// WOW, that's unusual.
counters.wows++;
}
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_23
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_23_AuxCounters.class.getSimpleName())
.output("JMHSample_23_AuxCounters.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,109 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/16 17:17
**/
public class JMHSample_24_Inheritance {
/*
* In very special circumstances, you might want to provide the benchmark
* body in the (abstract) superclass, and specialize it with the concrete
* pieces in the subclasses.
*
* The rule of thumb is: if some class has @Benchmark method, then all the subclasses
* are also having the "synthetic" @Benchmark method. The caveat is, because we only
* know the type hierarchy during the compilation, it is only possible during
* the same compilation session. That is, mixing in the subclass extending your
* benchmark class *after* the JMH compilation would have no effect.
*
* Note how annotations now have two possible places. The closest annotation
* in the hierarchy wins.
*
* 使
* @Benchmark@Benchmark
* 使
* JMHbenchmark
*
*
*/
@BenchmarkMode(Mode.AverageTime)
@Fork(1)
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static abstract class AbstractBenchmark {
int x;
@Setup
public void setup() {
x = 42;
}
@Benchmark
@Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
public double bench() {
return doWork() * doWork();
}
protected abstract double doWork();
}
@BenchmarkMode(Mode.Throughput)
public static class BenchmarkLog extends AbstractBenchmark {
@Override
protected double doWork() {
return Math.log(x);
}
}
public static class BenchmarkSin extends AbstractBenchmark {
@Override
protected double doWork() {
return Math.sin(x);
}
}
public static class BenchmarkCos extends AbstractBenchmark {
@Override
protected double doWork() {
return Math.cos(x);
}
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test, and observe the three distinct benchmarks running the squares
* of Math.sampleLog, Math.sin, and Math.cos, accordingly.
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_24
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_24_Inheritance.class.getSimpleName())
.output("JMHSample_24_Inheritance.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,121 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.LinkedList;
import java.util.List;
/**
* desc
*
* @author childe
* @date 2018/10/17 10:05
**/
@State(Scope.Thread)
public class JMHSample_26_BatchSize {
/*
* Sometimes you need to evaluate operation which doesn't have
* the steady state. The cost of a benchmarked operation may
* significantly vary from invocation to invocation.
*
* In this case, using the timed measurements is not a good idea,
* and the only acceptable benchmark mode is a single shot. On the
* other hand, the operation may be too small for reliable single
* shot measurement.
*
* We can use "batch size" parameter to describe the number of
* benchmark calls to do per one invocation without looping the method
* manually and protect from problems described in JMHSample_11_Loops.
*
*
*
* 使single shot
*
*
* 使batch sizeJMHSample_11_Loops
*/
/*
* Suppose we want to measure insertion in the middle of the list.
*/
List<String> list = new LinkedList<>();
@Benchmark
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.AverageTime)
public List<String> measureWrong_1() {
list.add(list.size() / 2, "something");
return list;
}
@Benchmark
@Warmup(iterations = 5, time = 5)
@Measurement(iterations = 5, time = 5)
@BenchmarkMode(Mode.AverageTime)
public List<String> measureWrong_5() {
list.add(list.size() / 2, "something");
return list;
}
/*
* This is what you do with JMH.
*/
@Benchmark
@Warmup(iterations = 5, batchSize = 5000)
@Measurement(iterations = 5, batchSize = 5000)
@BenchmarkMode(Mode.SingleShotTime)
public List<String> measureRight() {
list.add(list.size() / 2, "something");
return list;
}
@Setup(Level.Iteration)
public void setup(){
list.clear();
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can see completely different results for measureWrong_1 and measureWrong_5; this
* is because the workload has no steady state. The result of the workload is dependent
* on the measurement time. measureRight does not have this drawback, because it measures
* the N invocations of the test method and measures it's time.
*
* We measure batch of 5000 invocations and consider the batch as the single operation.
*
* measureWrong_1measureWrong_5;
* measureRightN
*
* 5000
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_26 -f 1
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_26_BatchSize.class.getSimpleName())
.forks(1)
.output("JMHSample_26_BatchSize.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,76 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.math.BigInteger;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/17 14:30
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Benchmark)
public class JMHSample_27_Params {
/**
* In many cases, the experiments require walking the configuration space
* for a benchmark. This is needed for additional control, or investigating
* how the workload performance changes with different settings.
*
*
*
* argcertainty
*/
@Param({"1", "31", "65", "101", "103"})
public int arg;
@Param({"0", "1", "2", "4", "8", "16", "32"})
public int certainty;
@Benchmark
public boolean bench() {
// 该计算的时常随着certainty的变大而变长
return BigInteger.valueOf(arg).isProbablePrime(certainty);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note the performance is different with different parameters.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_27
*
* You can juggle parameters through the command line, e.g. with "-p arg=41,42"
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_27_Params.class.getSimpleName())
// .param("arg", "41", "42") // Use this to selectively constrain/override parameters
.output("JMHSample_27_Params.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,126 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/17 15:14
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Thread)
public class JMHSample_28_BlackholeHelpers {
/**
* Sometimes you need the black hole not in @Benchmark method, but in
* helper methods, because you want to pass it through to the concrete
* implementation which is instantiated in helper methods. In this case,
* you can request the black hole straight in the helper method signature.
* This applies to both @Setup and @TearDown methods, and also to other
* JMH infrastructure objects, like Control.
*
* Below is the variant of {@link com.cxd.benchmark.JMHSample_08_DeadCode}
* test, but wrapped in the anonymous classes.
*
* Blackhole@Benchmarkhelperhelper
* helperBlackhole
* @Setup@TearDownJMHControl
*
* {@link com.cxd.benchmark.JMHSample_08_DeadCode}
*/
public interface Worker {
void work();
}
private Worker workerBaseline;
private Worker workerRight;
private Worker workerWrong;
@Setup
public void setup(final Blackhole bh) {
workerBaseline = new Worker() {
double x;
@Override
public void work() {
// do nothing
}
};
workerWrong = new Worker() {
double x;
@Override
public void work() {
Math.log(x);
}
};
workerRight = new Worker() {
double x;
@Override
public void work() {
bh.consume(Math.log(x));
}
};
}
@Benchmark
public void baseline() {
workerBaseline.work();
}
@Benchmark
public void measureWrong() {
workerWrong.work();
}
@Benchmark
public void measureRight() {
workerRight.work();
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You will see measureWrong() running on-par with baseline().
* Both measureRight() are measuring twice the baseline, so the logs are intact.
*
* measureWrong()baseline()
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_28
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_28_BlackholeHelpers.class.getSimpleName())
.output("JMHSample_28_BlackholeHelpers.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,106 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/17 15:31
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Group)
@Timeout(time = 10)
public class JMHSample_30_Interrupts {
/*
* JMH can also detect when threads are stuck in the benchmarks, and try
* to forcefully interrupt the benchmark thread. JMH tries to do that
* when it is arguably sure it would not affect the measurement.
*
* JMH线线
* JMH
*/
/*
* In this example, we want to measure the simple performance characteristics
* of the ArrayBlockingQueue. Unfortunately, doing that without a harness
* support will deadlock one of the threads, because the executions of
* take/put are not paired perfectly. Fortunately for us, both methods react
* to interrupts well, and therefore we can rely on JMH to terminate the
* measurement for us. JMH will notify users about the interrupt actions
* nevertheless, so users can see if those interrupts affected the measurement.
* JMH will start issuing interrupts after the default or user-specified timeout
* had been reached.
*
* This is a variant of org.openjdk.jmh.samples.JMHSample_18_Control, but without
* the explicit control objects. This example is suitable for the methods which
* react to interrupts gracefully.
*
* ArrayBlockingQueue
* 使线take / put
* JMH
* JMH
* JMH
*
* {@link com.cxd.benchmark.JMHSample_18_Control}
*
*/
private BlockingQueue<Integer> q;
@Setup
public void setup() {
q = new ArrayBlockingQueue<>(1);
}
@Group("Q")
@Benchmark
public Integer take() throws InterruptedException {
return q.take();
}
@Group("Q")
@Benchmark
public void put() throws InterruptedException {
q.put(42);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_30 -t 2 -f 5 -to 10
* (we requested 2 threads, 5 forks, and 10 sec timeout)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_30_Interrupts.class.getSimpleName())
.threads(2)
.forks(5)
// .timeout(TimeValue.seconds(10))
.output("JMHSample_30_Interrupts_annotation.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,124 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.BenchmarkParams;
import org.openjdk.jmh.infra.ThreadParams;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* JMHJMH
*
* @author childe
* @date 2018/10/17 16:35
**/
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class JMHSample_31_InfraParams {
/*
* There is a way to query JMH about the current running mode. This is
* possible with three infrastructure objects we can request to be injected:
* - BenchmarkParams: covers the benchmark-global configuration
* - IterationParams: covers the current iteration configuration
* - ThreadParams: covers the specifics about threading
*
* Suppose we want to check how the ConcurrentHashMap scales under different
* parallelism levels. We can put concurrencyLevel in @Param, but it sometimes
* inconvenient if, say, we want it to follow the @Threads count. Here is
* how we can query JMH about how many threads was requested for the current run,
* and put that into concurrencyLevel argument for CHM constructor.
*
* JMH
* - BenchmarkParams: benchmark
* - IterationParams:
* - ThreadParams: 线
*
* ConcurrentHashMapconcurrencyLevel@Param
* 便@ThreadsJMH线
* ConcurrentHashMapconcurrencyLevel
*/
static final int THREAD_SLICE = 1000;
private ConcurrentHashMap<String, String> mapSingle;
private ConcurrentHashMap<String, String> mapFollowThreads;
@Setup
public void setup(BenchmarkParams params) {
int capacity = 16 * THREAD_SLICE * params.getThreads();
// 并发级别数量似乎只会影响initcapacity仅在initcapacity小于并发数量时。这么测试好像没什么意义。
mapSingle = new ConcurrentHashMap<>(capacity, 0.75f, 1);
mapFollowThreads = new ConcurrentHashMap<>(capacity, 0.75f, params.getThreads());
}
/*
* Here is another neat trick. Generate the distinct set of keys for all threads:
*
* 线
*/
@State(Scope.Thread)
public static class Ids {
private List<String> ids;
@Setup
public void setup(ThreadParams threads) {
ids = new ArrayList<>();
for (int c = 0; c < THREAD_SLICE; c++) {
ids.add("ID" + (THREAD_SLICE * threads.getThreadIndex() + c));
}
}
}
@Benchmark
public void measureDefault(Ids ids) {
for (String s : ids.ids) {
mapSingle.remove(s);
mapSingle.put(s, s);
}
}
@Benchmark
public void measureFollowThreads(Ids ids) {
for (String s : ids.ids) {
mapFollowThreads.remove(s);
mapFollowThreads.put(s, s);
}
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_31 -t 4 -f 5
* (we requested 4 threads, and 5 forks; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_31_InfraParams.class.getSimpleName())
.threads(4)
.forks(5)
.output("JMHSample_31_InfraParams.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,131 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.WarmupMode;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author childe
* @date 2018/10/17 17:09
**/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_32_BulkWarmup {
/*
* This is an addendum to JMHSample_12_Forking test.
*
* Sometimes you want an opposite configuration: instead of separating the profiles
* for different benchmarks, you want to mix them together to test the worst-case
* scenario.
*
* JMH has a bulk warmup feature for that: it does the warmups for all the tests
* first, and then measures them. JMH still forks the JVM for each test, but once the
* new JVM has started, all the warmups are being run there, before running the
* measurement. This helps to dodge the type profile skews, as each test is still
* executed in a different JVM, and we only "mix" the warmup code we want.
*
* JMHSample_12_Forking
*
*
*
* JMHJMHforkJVMJVM
*
* JVM
*/
/*
* These test classes are borrowed verbatim from JMHSample_12_Forking.
*/
public interface Counter {
int inc();
}
public class Counter1 implements Counter {
private int x;
@Override
public int inc() {
return x++;
}
}
public class Counter2 implements Counter {
private int x;
@Override
public int inc() {
return x++;
}
}
Counter c1 = new Counter1();
Counter c2 = new Counter2();
/*
* And this is our test payload. Notice we have to break the inlining of the payload,
* so that in could not be inlined in either measure_c1() or measure_c2() below, and
* specialized for that only call.
*/
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public int measure(Counter c) {
int s = 0;
for (int i = 0; i < 10; i++) {
s += c.inc();
}
return s;
}
@Benchmark
public int measure_c1() {
return measure(c1);
}
@Benchmark
public int measure_c2() {
return measure(c2);
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* Note how JMH runs the warmups first, and only then a given test. Note how JMH re-warmups
* the JVM for each test. The scores for C1 and C2 cases are equally bad, compare them to
* the scores from JMHSample_12_Forking.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_32 -f 1 -wm BULK
* (we requested a single fork, and bulk warmup mode; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_32_BulkWarmup.class.getSimpleName())
// .includeWarmup(...) <-- this may include other benchmarks into warmup
// .warmupMode(WarmupMode.BULK) // see other WarmupMode.* as well
.warmupMode(WarmupMode.INDI) // see other WarmupMode.* as well
.forks(1)
.output("JMHSample_32_BulkWarmup_indi.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,199 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author childe
* @date 2018/10/17 17:37
**/
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_34_SafeLooping {
/*
* JMHSample_11_Loops warns about the dangers of using loops in @Benchmark methods.
* Sometimes, however, one needs to traverse through several elements in a dataset.
* This is hard to do without loops, and therefore we need to devise a scheme for
* safe looping.
*
* JMHSample_11_Loops@Benchmark使
* 便
*/
/*
* Suppose we want to measure how much it takes to execute work() with different
* arguments. This mimics a frequent use case when multiple instances with the same
* implementation, but different data, is measured.
*
* work()仿
*/
static final int BASE = 42;
static int work(int x) {
return BASE + x;
}
/*
* Every benchmark requires control. We do a trivial control for our benchmarks
* by checking the benchmark costs are growing linearly with increased task size.
* If it doesn't, then something wrong is happening.
*
* 线
*
*/
@Param({"1", "10", "100", "1000"})
int size;
int[] xs;
@Setup
public void setup() {
xs = new int[size];
for (int c = 0; c < size; c++) {
xs[c] = c;
}
}
/*
* First, the obviously wrong way: "saving" the result into a local variable would not
* work. A sufficiently smart compiler will inline work(), and figure out only the last
* work() call needs to be evaluated. Indeed, if you run it with varying $size, the score
* will stay the same!
*
* work()
* work()$sizex
*/
@Benchmark
public int measureWrong_1() {
int acc = 0;
for (int x : xs) {
acc = work(x);
}
return acc;
}
/*
* Second, another wrong way: "accumulating" the result into a local variable. While
* it would force the computation of each work() method, there are software pipelining
* effects in action, that can merge the operations between two otherwise distinct work()
* bodies. This will obliterate the benchmark setup.
*
* In this example, HotSpot does the unrolled loop, merges the $BASE operands into a single
* addition to $acc, and then does a bunch of very tight stores of $x-s. The final performance
* depends on how much of the loop unrolling happened *and* how much data is available to make
* the large strides.
*
*
* work()pipeliningwork()
*
* HotSpotunrolled$BASE$acc$x-s
* unrolled
*/
@Benchmark
public int measureWrong_2() {
int acc = 0;
for (int x : xs) {
acc += work(x);
}
return acc;
}
/*
* Now, let's see how to measure these things properly. A very straight-forward way to
* break the merging is to sink each result to Blackhole. This will force runtime to compute
* every work() call in full. (We would normally like to care about several concurrent work()
* computations at once, but the memory effects from Blackhole.consume() prevent those optimization
* on most runtimes).
*
* Blackhole
* work()work()Blackhole.consume()
*/
@Benchmark
public void measureRight_1(Blackhole bh) {
for (int x : xs) {
bh.consume(work(x));
}
}
/*
* DANGEROUS AREA, PLEASE READ THE DESCRIPTION BELOW.
*
* Sometimes, the cost of sinking the value into a Blackhole is dominating the nano-benchmark score.
* In these cases, one may try to do a make-shift "sinker" with non-inlineable method. This trick is
* *very* VM-specific, and can only be used if you are verifying the generated code (that's a good
* strategy when dealing with nano-benchmarks anyway).
*
* You SHOULD NOT use this trick in most cases. Apply only where needed.
*
*
*
* Blackholenano-benchmark
* non-inlineableVM使nano-benchmarks
*
* 使使
*/
@Benchmark
public void measureRight_2() {
for (int x : xs) {
sink(work(x));
}
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public static void sink(int v) {
// IT IS VERY IMPORTANT TO MATCH THE SIGNATURE TO AVOID AUTOBOXING.
// The method intentionally does nothing.
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You might notice measureWrong_1 does not depend on $size, measureWrong_2 has troubles with
* linearity, and otherwise much faster than both measureRight_*. You can also see measureRight_2
* is marginally faster than measureRight_1.
*
* measureWrong_1$sizemeasureWrong_2线measureRight_*
* measureRight_2measureRight_1
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_34
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHSample_34_SafeLooping.class.getSimpleName())
.forks(3)
.output("JMHSample_34_SafeLooping.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,612 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.profile.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* {@link org.openjdk.jmh.profile}
*
* @author childe
* @date 2018/10/18 19:21
**/
public class JMHSample_35_Profilers {
/*
* This sample serves as the profiler overview.
*
* JMH has a few very handy profilers that help to understand your benchmarks. While
* these profilers are not the substitute for full-fledged external profilers, in many
* cases, these are handy to quickly dig into the benchmark behavior. When you are
* doing many cycles of tuning up the benchmark code itself, it is important to have
* a quick turnaround for the results.
*
* Use -lprof to list the profilers. There are quite a few profilers, and this sample
* would expand on a handful of most useful ones. Many profilers have their own options,
* usually accessible via -prof <profiler-name>:help.
*
* Since profilers are reporting on different things, it is hard to construct a single
* benchmark sample that will show all profilers in action. Therefore, we have a couple
* of benchmarks in this sample.
*
* profiler
*
* JMH便profilerbenchmark
*
*
* 使-lprofprofilerprofiler-prof <profiler-name>:help
*
* profilerprofiler
*
* */
/*
* ================================ MAPS BENCHMARK ================================
*/
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static class Maps {
private Map<Integer, Integer> map;
@Param({"hashmap", "treemap"})
private String type;
private int begin;
private int end;
@Setup
public void setup() {
switch (type) {
case "hashmap":
map = new HashMap<>();
break;
case "treemap":
map = new TreeMap<>();
break;
default:
throw new IllegalStateException("Unknown type: " + type);
}
begin = 1;
end = 256;
for (int i = begin; i < end; i++) {
map.put(i, i);
}
}
@Benchmark
public void test(Blackhole bh) {
for (int i = begin; i < end; i++) {
bh.consume(map.get(i));
}
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_35.*Maps -prof stack
* $ java -jar target/benchmarks.jar JMHSample_35.*Maps -prof gc
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(Maps.class.getSimpleName())
// .addProfiler(StackProfiler.class)
.addProfiler(GCProfiler.class)
.build();
new Runner(opt).run();
}
/*
Running this benchmark will yield something like:
Benchmark (type) Mode Cnt Score Error Units
JMHSample_35_Profilers.Maps.test hashmap avgt 5 1553.201 ± 6.199 ns/op
JMHSample_35_Profilers.Maps.test treemap avgt 5 5177.065 ± 361.278 ns/op
Running with -prof stack will yield:
....[Thread state: RUNNABLE]........................................................................
99.0% 99.0% org.openjdk.jmh.samples.JMHSample_35_Profilers$Maps.test
0.4% 0.4% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Maps_test.test_avgt_jmhStub
0.2% 0.2% sun.reflect.NativeMethodAccessorImpl.invoke0
0.2% 0.2% java.lang.Integer.valueOf
0.2% 0.2% sun.misc.Unsafe.compareAndSwapInt
....[Thread state: RUNNABLE]........................................................................
78.0% 78.0% java.util.TreeMap.getEntry
21.2% 21.2% org.openjdk.jmh.samples.JMHSample_35_Profilers$Maps.test
0.4% 0.4% java.lang.Integer.valueOf
0.2% 0.2% sun.reflect.NativeMethodAccessorImpl.invoke0
0.2% 0.2% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Maps_test.test_avgt_jmhStub
Stack profiler is useful to quickly see if the code we are stressing actually executes. As many other
sampling profilers, it is susceptible for sampling bias: it can fail to notice quickly executing methods,
for example. In the benchmark above, it does not notice HashMap.get.
Stack profiler
HashMap.get
Next up, GC profiler. Running with -prof gc will yield:
Benchmark (type) Mode Cnt Score Error Units
JMHSample_35_Profilers.Maps.test hashmap avgt 5 1553.201 ± 6.199 ns/op
JMHSample_35_Profilers.Maps.test:·gc.alloc.rate hashmap avgt 5 1257.046 ± 5.675 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.alloc.rate.norm hashmap avgt 5 2048.001 ± 0.001 B/op
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space hashmap avgt 5 1259.148 ± 315.277 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space.norm hashmap avgt 5 2051.519 ± 520.324 B/op
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space hashmap avgt 5 0.175 ± 0.386 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space.norm hashmap avgt 5 0.285 ± 0.629 B/op
JMHSample_35_Profilers.Maps.test:·gc.count hashmap avgt 5 29.000 counts
JMHSample_35_Profilers.Maps.test:·gc.time hashmap avgt 5 16.000 ms
JMHSample_35_Profilers.Maps.test treemap avgt 5 5177.065 ± 361.278 ns/op
JMHSample_35_Profilers.Maps.test:·gc.alloc.rate treemap avgt 5 377.251 ± 26.188 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.alloc.rate.norm treemap avgt 5 2048.003 ± 0.001 B/op
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space treemap avgt 5 392.743 ± 174.156 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space.norm treemap avgt 5 2131.767 ± 913.941 B/op
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space treemap avgt 5 0.131 ± 0.215 MB/sec
JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space.norm treemap avgt 5 0.709 ± 1.125 B/op
JMHSample_35_Profilers.Maps.test:·gc.count treemap avgt 5 25.000 counts
JMHSample_35_Profilers.Maps.test:·gc.time treemap avgt 5 26.000 ms
There, we can see that the tests are producing quite some garbage. "gc.alloc" would say we are allocating 1257
and 377 MB of objects per second, or 2048 bytes per benchmark operation. "gc.churn" would say that GC removes
the same amount of garbage from Eden space every second. In other words, we are producing 2048 bytes of garbage per
benchmark operation.
"gc.alloc"1257277MB2048
"gc.churn"GCEdenGC2048
If you look closely at the test, you can get a (correct) hypothesis this is due to Integer autoboxing.
Integer
Note that "gc.alloc" counters generally produce more accurate data, but they can also fail when threads come and
go over the course of the benchmark. "gc.churn" values are updated on each GC event, and so if you want a more accurate
data, running longer and/or with small heap would help. But anyhow, always cross-reference "gc.alloc" and "gc.churn"
values with each other to get a complete picture.
"gc.alloc"线
"gc.churn"GC/使
gc.allocgc.churn
It is also worth noticing that non-normalized counters are dependent on benchmark performance! Here, "treemap"
tests are 3x slower, and thus both allocation and churn rates are also comparably lower. It is often useful to look
into non-normalized counters to see if the test is allocation/GC-bound (figure the allocation pressure "ceiling"
for your configuration!), and normalized counters to see the more precise benchmark behavior.
benchmark
"treemap"3
allocation/GC-bound benchmark
As most profilers, both "stack" and "gc" profile are able to aggregate samples from multiple forks. It is a good
idea to run multiple forks with the profilers enabled, as it improves results error estimates.
"stack""gc"forkfork
*/
}
/*
* ================================ CLASSLOADER BENCHMARK ================================
*/
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static class Classy {
/**
* Our own crippled classloader, that can only load a simple class over and over again.
*/
public static class XLoader extends URLClassLoader {
private static final byte[] X_BYTECODE = new byte[]{
(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, 0x00, 0x00, 0x00, 0x34, 0x00, 0x0D, 0x0A, 0x00, 0x03, 0x00,
0x0A, 0x07, 0x00, 0x0B, 0x07, 0x00, 0x0C, 0x01, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69, 0x74, 0x3E, 0x01, 0x00, 0x03,
0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43, 0x6F, 0x64, 0x65, 0x01, 0x00, 0x0F, 0x4C, 0x69, 0x6E, 0x65, 0x4E, 0x75,
0x6D, 0x62, 0x65, 0x72, 0x54, 0x61, 0x62, 0x6C, 0x65, 0x01, 0x00, 0x0A, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x46,
0x69, 0x6C, 0x65, 0x01, 0x00, 0x06, 0x58, 0x2E, 0x6A, 0x61, 0x76, 0x61, 0x0C, 0x00, 0x04, 0x00, 0x05, 0x01, 0x00,
0x01, 0x58, 0x01, 0x00, 0x10, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x4F, 0x62, 0x6A, 0x65,
0x63, 0x74, 0x00, 0x20, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x2A,
(byte) 0xB7, 0x00, 0x01, (byte) 0xB1, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09,
};
public XLoader() {
super(new URL[0], ClassLoader.getSystemClassLoader());
}
@Override
protected Class<?> findClass(final String name) {
return defineClass(name, X_BYTECODE, 0, X_BYTECODE.length);
}
}
@Benchmark
public Class<?> load() throws ClassNotFoundException {
return Class.forName("X", true, new XLoader());
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_35.*Classy -prof cl
* $ java -jar target/benchmarks.jar JMHSample_35.*Classy -prof comp
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(Classy.class.getSimpleName())
.addProfiler(ClassloaderProfiler.class)
// .addProfiler(CompilerProfiler.class)
.build();
new Runner(opt).run();
}
/*
Running with -prof cl will yield:
Benchmark Mode Cnt Score Error Units
JMHSample_35_Profilers.Classy.load avgt 15 34215.363 ± 545.892 ns/op
JMHSample_35_Profilers.Classy.load:·class.load avgt 15 29374.097 ± 716.743 classes/sec
JMHSample_35_Profilers.Classy.load:·class.load.norm avgt 15 1.000 ± 0.001 classes/op
JMHSample_35_Profilers.Classy.load:·class.unload avgt 15 29598.233 ± 3420.181 classes/sec
JMHSample_35_Profilers.Classy.load:·class.unload.norm avgt 15 1.008 ± 0.119 classes/op
Here, we can see the benchmark indeed load class per benchmark op, and this adds up to more than 29K classloads
per second. We can also see the runtime is able to successfully keep the number of loaded classes at bay,
since the class unloading happens at the same rate.
29K
This profiler is handy when doing the classloading performance work, because it says if the classes
were actually loaded, and not reused across the Class.forName calls. It also helps to see if the benchmark
performs any classloading in the measurement phase. For example, if you have non-classloading benchmark,
you would expect these metrics be zero.
便Class.forName
Another useful profiler that could tell if compiler is doing a heavy work in background, and thus interfering
with measurement, -prof comp:
profiler-prof comp:
Benchmark Mode Cnt Score Error Units
JMHSample_35_Profilers.Classy.load avgt 5 33523.875 ± 3026.025 ns/op
JMHSample_35_Profilers.Classy.load:·compiler.time.profiled avgt 5 5.000 ms
JMHSample_35_Profilers.Classy.load:·compiler.time.total avgt 5 479.000 ms
We seem to be at proper steady state: out of 479 ms of total compiler work, only 5 ms happen during the
measurement window. It is expected to have some level of background compilation even at steady state.
479ms5ms
使
As most profilers, both "cl" and "comp" are able to aggregate samples from multiple forks. It is a good
idea to run multiple forks with the profilers enabled, as it improves results error estimates.
profilers"cl""comp"forkprofilerfork
*/
}
/*
* ================================ ATOMIC LONG BENCHMARK ================================
*/
@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static class Atomic {
private AtomicLong n;
@Setup
public void setup() {
n = new AtomicLong();
}
@Benchmark
public long test() {
return n.incrementAndGet();
}
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perf -f 1 (Linux)
* $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perfnorm -f 3 (Linux)
* $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perfasm -f 1 (Linux)
* $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof xperfasm -f 1 (Windows)
* $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof dtraceasm -f 1 (Mac OS X)
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(Atomic.class.getSimpleName())
// .addProfiler(LinuxPerfProfiler.class)
// .addProfiler(LinuxPerfNormProfiler.class)
// .addProfiler(LinuxPerfAsmProfiler.class)
// .addProfiler(WinPerfAsmProfiler.class)
// 需要开启用户sudo免密
.addProfiler(DTraceAsmProfiler.class)
.build();
new Runner(opt).run();
}
/*
Dealing with nanobenchmarks like these requires looking into the abyss of runtime, hardware, and
generated code. Luckily, JMH has a few handy tools that ease the pain. If you are running Linux,
then perf_events are probably available as standard package. This kernel facility taps into
hardware counters, and provides the data for user space programs like JMH. Windows has less
sophisticated facilities, but also usable, see below.
One can simply run "perf stat java -jar ..." to get the first idea how the workload behaves. In
JMH case, however, this will cause perf to profile both host and forked JVMs.
-prof perf avoids that: JMH invokes perf for the forked VM alone. For the benchmark above, it
would print something like:
Perf stats:
--------------------------------------------------
4172.776137 task-clock (msec) # 0.411 CPUs utilized
612 context-switches # 0.147 K/sec
31 cpu-migrations # 0.007 K/sec
195 page-faults # 0.047 K/sec
16,599,643,026 cycles # 3.978 GHz [30.80%]
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
17,815,084,879 instructions # 1.07 insns per cycle [38.49%]
3,813,373,583 branches # 913.870 M/sec [38.56%]
1,212,788 branch-misses # 0.03% of all branches [38.91%]
7,582,256,427 L1-dcache-loads # 1817.077 M/sec [39.07%]
312,913 L1-dcache-load-misses # 0.00% of all L1-dcache hits [38.66%]
35,688 LLC-loads # 0.009 M/sec [32.58%]
<not supported> LLC-load-misses:HG
<not supported> L1-icache-loads:HG
161,436 L1-icache-load-misses:HG # 0.00% of all L1-icache hits [32.81%]
7,200,981,198 dTLB-loads:HG # 1725.705 M/sec [32.68%]
3,360 dTLB-load-misses:HG # 0.00% of all dTLB cache hits [32.65%]
193,874 iTLB-loads:HG # 0.046 M/sec [32.56%]
4,193 iTLB-load-misses:HG # 2.16% of all iTLB cache hits [32.44%]
<not supported> L1-dcache-prefetches:HG
0 L1-dcache-prefetch-misses:HG # 0.000 K/sec [32.33%]
10.159432892 seconds time elapsed
We can already see this benchmark goes with good IPC, does lots of loads and lots of stores,
all of them are more or less fulfilled without misses. The data like this is not handy though:
you would like to normalize the counters per benchmark op.
This is exactly what -prof perfnorm does:
Benchmark Mode Cnt Score Error Units
JMHSample_35_Profilers.Atomic.test avgt 15 6.551 ± 0.023 ns/op
JMHSample_35_Profilers.Atomic.test:·CPI avgt 3 0.933 ± 0.026 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-load-misses avgt 3 0.001 ± 0.022 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-loads avgt 3 12.267 ± 1.324 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-store-misses avgt 3 0.001 ± 0.006 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-stores avgt 3 4.090 ± 0.402 #/op
JMHSample_35_Profilers.Atomic.test:·L1-icache-load-misses avgt 3 0.001 ± 0.011 #/op
JMHSample_35_Profilers.Atomic.test:·LLC-loads avgt 3 0.001 ± 0.004 #/op
JMHSample_35_Profilers.Atomic.test:·LLC-stores avgt 3 ∠10⁻⁴ #/op
JMHSample_35_Profilers.Atomic.test:·branch-misses avgt 3 ∠10⁻⁴ #/op
JMHSample_35_Profilers.Atomic.test:·branches avgt 3 6.152 ± 0.385 #/op
JMHSample_35_Profilers.Atomic.test:·bus-cycles avgt 3 0.670 ± 0.048 #/op
JMHSample_35_Profilers.Atomic.test:·context-switches avgt 3 ∠10⁻⁠#/op
JMHSample_35_Profilers.Atomic.test:·cpu-migrations avgt 3 ∠10⁻⁷ #/op
JMHSample_35_Profilers.Atomic.test:·cycles avgt 3 26.790 ± 1.393 #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-load-misses avgt 3 ∠10⁻⁴ #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-loads avgt 3 12.278 ± 0.277 #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-store-misses avgt 3 ∠10⁻⁵ #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-stores avgt 3 4.113 ± 0.437 #/op
JMHSample_35_Profilers.Atomic.test:·iTLB-load-misses avgt 3 ∠10⁻⁵ #/op
JMHSample_35_Profilers.Atomic.test:·iTLB-loads avgt 3 0.001 ± 0.034 #/op
JMHSample_35_Profilers.Atomic.test:·instructions avgt 3 28.729 ± 1.297 #/op
JMHSample_35_Profilers.Atomic.test:·minor-faults avgt 3 ∠10⁻⁷ #/op
JMHSample_35_Profilers.Atomic.test:·page-faults avgt 3 ∠10⁻⁷ #/op
JMHSample_35_Profilers.Atomic.test:·ref-cycles avgt 3 26.734 ± 2.081 #/op
It is customary to trim the lines irrelevant to the particular benchmark. We show all of them here for
completeness.
We can see that the benchmark does ~12 loads per benchmark op, and about ~4 stores per op, most of
them fitting in the cache. There are also ~6 branches per benchmark op, all are predicted as well.
It is also easy to see the benchmark op takes ~28 instructions executed in ~27 cycles.
The output would get more interesting when we run with more threads, say, -t 8:
Benchmark Mode Cnt Score Error Units
JMHSample_35_Profilers.Atomic.test avgt 15 143.595 ± 1.968 ns/op
JMHSample_35_Profilers.Atomic.test:·CPI avgt 3 17.741 ± 28.761 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-load-misses avgt 3 0.175 ± 0.406 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-loads avgt 3 11.872 ± 0.786 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-store-misses avgt 3 0.184 ± 0.505 #/op
JMHSample_35_Profilers.Atomic.test:·L1-dcache-stores avgt 3 4.422 ± 0.561 #/op
JMHSample_35_Profilers.Atomic.test:·L1-icache-load-misses avgt 3 0.015 ± 0.083 #/op
JMHSample_35_Profilers.Atomic.test:·LLC-loads avgt 3 0.015 ± 0.128 #/op
JMHSample_35_Profilers.Atomic.test:·LLC-stores avgt 3 1.036 ± 0.045 #/op
JMHSample_35_Profilers.Atomic.test:·branch-misses avgt 3 0.224 ± 0.492 #/op
JMHSample_35_Profilers.Atomic.test:·branches avgt 3 6.524 ± 2.873 #/op
JMHSample_35_Profilers.Atomic.test:·bus-cycles avgt 3 13.475 ± 14.502 #/op
JMHSample_35_Profilers.Atomic.test:·context-switches avgt 3 ∠10⁻⁴ #/op
JMHSample_35_Profilers.Atomic.test:·cpu-migrations avgt 3 ∠10⁻⁠#/op
JMHSample_35_Profilers.Atomic.test:·cycles avgt 3 537.874 ± 595.723 #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-load-misses avgt 3 0.001 ± 0.006 #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-loads avgt 3 12.032 ± 2.430 #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-store-misses avgt 3 ∠10⁻⁴ #/op
JMHSample_35_Profilers.Atomic.test:·dTLB-stores avgt 3 4.557 ± 0.948 #/op
JMHSample_35_Profilers.Atomic.test:·iTLB-load-misses avgt 3 ∠10⁻³ #/op
JMHSample_35_Profilers.Atomic.test:·iTLB-loads avgt 3 0.016 ± 0.052 #/op
JMHSample_35_Profilers.Atomic.test:·instructions avgt 3 30.367 ± 15.052 #/op
JMHSample_35_Profilers.Atomic.test:·minor-faults avgt 3 ∠10⁻⁵ #/op
JMHSample_35_Profilers.Atomic.test:·page-faults avgt 3 ∠10⁻⁵ #/op
JMHSample_35_Profilers.Atomic.test:·ref-cycles avgt 3 538.697 ± 590.183 #/op
Note how this time the CPI is awfully high: 17 cycles per instruction! Indeed, we are making almost the
same ~30 instructions, but now they take >530 cycles. Other counters highlight why: we now have cache
misses on both loads and stores, on all levels of cache hierarchy. With a simple constant-footprint
like ours, that's an indication of sharing problems. Indeed, our AtomicLong is heavily-contended
with 8 threads.
"perfnorm", again, can (and should!) be used with multiple forks, to properly estimate the metrics.
The last, but not the least player on our field is -prof perfasm. It is important to follow up on
generated code when dealing with fine-grained benchmarks. We could employ PrintAssembly to dump the
generated code, but it will dump *all* the generated code, and figuring out what is related to our
benchmark is a daunting task. But we have "perf" that can tell what program addresses are really hot!
This enables us to contrast the assembly output.
-prof perfasm would indeed contrast out the hottest loop in the generated code! It will also point
fingers at "lock xadd" as the hottest instruction in our code. Hardware counters are not very precise
about the instruction addresses, so sometimes they attribute the events to the adjacent code lines.
Hottest code regions (>10.00% "cycles" events):
....[Hottest Region 1]..............................................................................
[0x7f1824f87c45:0x7f1824f87c79] in org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@29 (line 201)
; implicit exception: dispatches to 0x00007f1824f87d21
0x00007f1824f87c25: test %r11d,%r11d
0x00007f1824f87c28: jne 0x00007f1824f87cbd ;*ifeq
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@32 (line 201)
0x00007f1824f87c2e: mov $0x1,%ebp
0x00007f1824f87c33: nopw 0x0(%rax,%rax,1)
0x00007f1824f87c3c: xchg %ax,%ax ;*aload
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@13 (line 199)
0x00007f1824f87c40: mov 0x8(%rsp),%r10
0.00% 0x00007f1824f87c45: mov 0xc(%r10),%r11d ;*getfield n
; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@1 (line 280)
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
0.19% 0.02% 0x00007f1824f87c49: test %r11d,%r11d
0x00007f1824f87c4c: je 0x00007f1824f87cad
0x00007f1824f87c4e: mov $0x1,%edx
0x00007f1824f87c53: lock xadd %rdx,0x10(%r12,%r11,8)
;*invokevirtual getAndAddLong
; - java.util.concurrent.atomic.AtomicLong::incrementAndGet@8 (line 200)
; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@4 (line 280)
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
95.20% 95.06% 0x00007f1824f87c5a: add $0x1,%rdx ;*ladd
; - java.util.concurrent.atomic.AtomicLong::incrementAndGet@12 (line 200)
; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@4 (line 280)
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
0.24% 0.00% 0x00007f1824f87c5e: mov 0x10(%rsp),%rsi
0x00007f1824f87c63: callq 0x00007f1824e2b020 ; OopMap{[0]=Oop [8]=Oop [16]=Oop [24]=Oop off=232}
;*invokevirtual consume
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@19 (line 199)
; {optimized virtual_call}
0.20% 0.01% 0x00007f1824f87c68: mov 0x18(%rsp),%r10
0x00007f1824f87c6d: movzbl 0x94(%r10),%r11d ;*getfield isDone
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@29 (line 201)
0.00% 0x00007f1824f87c75: add $0x1,%rbp ; OopMap{r10=Oop [0]=Oop [8]=Oop [16]=Oop [24]=Oop off=249}
;*ifeq
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@32 (line 201)
0.20% 0.01% 0x00007f1824f87c79: test %eax,0x15f36381(%rip) # 0x00007f183aebe000
; {poll}
0x00007f1824f87c7f: test %r11d,%r11d
0x00007f1824f87c82: je 0x00007f1824f87c40 ;*aload_2
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@35 (line 202)
0x00007f1824f87c84: mov $0x7f1839be4220,%r10
0x00007f1824f87c8e: callq *%r10 ;*invokestatic nanoTime
; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@36 (line 202)
0x00007f1824f87c91: mov (%rsp),%r10
....................................................................................................
96.03% 95.10% <total for region 1>
perfasm would also print the hottest methods to show if we indeed spending time in our benchmark. Most of the time,
it can demangle VM and kernel symbols as well:
....[Hottest Methods (after inlining)]..............................................................
96.03% 95.10% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub
0.73% 0.78% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_AverageTime
0.63% 0.00% org.openjdk.jmh.infra.Blackhole::consume
0.23% 0.25% native_write_msr_safe ([kernel.kallsyms])
0.09% 0.05% _raw_spin_unlock ([kernel.kallsyms])
0.09% 0.00% [unknown] (libpthread-2.19.so)
0.06% 0.07% _raw_spin_lock ([kernel.kallsyms])
0.06% 0.04% _raw_spin_unlock_irqrestore ([kernel.kallsyms])
0.06% 0.05% _IO_fwrite (libc-2.19.so)
0.05% 0.03% __srcu_read_lock; __srcu_read_unlock ([kernel.kallsyms])
0.04% 0.05% _raw_spin_lock_irqsave ([kernel.kallsyms])
0.04% 0.06% vfprintf (libc-2.19.so)
0.04% 0.01% mutex_unlock ([kernel.kallsyms])
0.04% 0.01% _nv014306rm ([nvidia])
0.04% 0.04% rcu_eqs_enter_common.isra.47 ([kernel.kallsyms])
0.04% 0.02% mutex_lock ([kernel.kallsyms])
0.03% 0.07% __acct_update_integrals ([kernel.kallsyms])
0.03% 0.02% fget_light ([kernel.kallsyms])
0.03% 0.01% fput ([kernel.kallsyms])
0.03% 0.04% rcu_eqs_exit_common.isra.48 ([kernel.kallsyms])
1.63% 2.26% <...other 319 warm methods...>
....................................................................................................
100.00% 98.97% <totals>
....[Distribution by Area]..........................................................................
97.44% 95.99% <generated code>
1.60% 2.42% <native code in ([kernel.kallsyms])>
0.47% 0.78% <native code in (libjvm.so)>
0.22% 0.29% <native code in (libc-2.19.so)>
0.15% 0.07% <native code in (libpthread-2.19.so)>
0.07% 0.38% <native code in ([nvidia])>
0.05% 0.06% <native code in (libhsdis-amd64.so)>
0.00% 0.00% <native code in (nf_conntrack.ko)>
0.00% 0.00% <native code in (hid.ko)>
....................................................................................................
100.00% 100.00% <totals>
Since program addresses change from fork to fork, it does not make sense to run perfasm with more than
a single fork.
*/
}
}

@ -0,0 +1,138 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.profile.DTraceAsmProfiler;
import org.openjdk.jmh.profile.LinuxPerfNormProfiler;
import org.openjdk.jmh.profile.LinuxPerfProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
*
* @author childe
* @date 2018-10-20
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(5)
@State(Scope.Benchmark)
public class JMHSample_36_BranchPrediction {
/*
* This sample serves as a warning against regular data sets.
*
* It is very tempting to present a regular data set to benchmark, either due to
* naive generation strategy, or just from feeling better about regular data sets.
* Unfortunately, it frequently backfires: the regular datasets are known to be
* optimized well by software and hardware. This example exploits one of these
* optimizations: branch prediction.
*
* Imagine our benchmark selects the branch based on the array contents, as
* we are streaming through it:
*
*
*
*
*
*
*
*
*/
private static final int COUNT = 1024 * 1024;
private byte[] sorted;
private byte[] unsorted;
@Setup
public void setup() {
sorted = new byte[COUNT];
unsorted = new byte[COUNT];
Random random = new Random(1234);
random.nextBytes(sorted);
random.nextBytes(unsorted);
Arrays.sort(sorted);
}
@Benchmark
@OperationsPerInvocation(COUNT)
public void sorted(Blackhole bh1, Blackhole bh2) {
for (byte v : sorted) {
if (v > 0) {
bh1.consume(v);
} else {
bh2.consume(v);
}
}
}
@Benchmark
@OperationsPerInvocation(COUNT)
public void unsorted(Blackhole bh1, Blackhole bh2) {
for (byte v : unsorted) {
if (v > 0) {
bh1.consume(v);
} else {
bh2.consume(v);
}
}
}
/*
There is a substantial difference in performance for these benchmarks!
It is explained by good branch prediction in "sorted" case, and branch mispredicts in "unsorted"
case. -prof perfnorm conveniently highlights that, with larger "branch-misses", and larger "CPI"
for "unsorted" case:
Benchmark Mode Cnt Score Error Units
JMHSample_36_BranchPrediction.sorted avgt 25 2.160 ± 0.049 ns/op
JMHSample_36_BranchPrediction.sorted:·CPI avgt 5 0.286 ± 0.025 #/op
JMHSample_36_BranchPrediction.sorted:·branch-misses avgt 5 ∠10⁻⁴ #/op
JMHSample_36_BranchPrediction.sorted:·branches avgt 5 7.606 ± 1.742 #/op
JMHSample_36_BranchPrediction.sorted:·cycles avgt 5 8.998 ± 1.081 #/op
JMHSample_36_BranchPrediction.sorted:·instructions avgt 5 31.442 ± 4.899 #/op
JMHSample_36_BranchPrediction.unsorted avgt 25 5.943 ± 0.018 ns/op
JMHSample_36_BranchPrediction.unsorted:·CPI avgt 5 0.775 ± 0.052 #/op
JMHSample_36_BranchPrediction.unsorted:·branch-misses avgt 5 0.529 ± 0.026 #/op <--- OOPS
JMHSample_36_BranchPrediction.unsorted:·branches avgt 5 7.841 ± 0.046 #/op
JMHSample_36_BranchPrediction.unsorted:·cycles avgt 5 24.793 ± 0.434 #/op
JMHSample_36_BranchPrediction.unsorted:·instructions avgt 5 31.994 ± 2.342 #/op
It is an open question if you want to measure only one of these tests. In many cases, you have to measure
both to get the proper best-case and worst-case estimate!
*/
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_36
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + JMHSample_36_BranchPrediction.class.getSimpleName() + ".*")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,126 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/22 17:10
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(5)
@State(Scope.Benchmark)
public class JMHSample_37_CacheAccess {
/*
* This sample serves as a warning against subtle differences in cache access patterns.
*
* Many performance differences may be explained by the way tests are accessing memory.
* In the example below, we walLevelk the matrix either row-first, or col-first:
*/
private final static int COUNT = 4096;
private final static int MATRIX_SIZE = COUNT * COUNT;
private int[][] matrix;
@Setup
public void setup() {
matrix = new int[COUNT][COUNT];
Random random = new Random(1234);
for (int i = 0; i < COUNT; i++) {
for (int j = 0; j < COUNT; j++) {
matrix[i][j] = random.nextInt();
}
}
}
@Benchmark
@OperationsPerInvocation(MATRIX_SIZE)
public void colFirst(Blackhole bh) {
for (int c = 0; c < COUNT; c++) {
for (int r = 0; r < COUNT; r++) {
bh.consume(matrix[r][c]);
}
}
}
@Benchmark
@OperationsPerInvocation(MATRIX_SIZE)
public void rowFirst(Blackhole bh) {
for (int r = 0; r < COUNT; r++) {
for (int c = 0; c < COUNT; c++) {
bh.consume(matrix[r][c]);
}
}
}
/*
Notably, colFirst accesses are much slower, and that's not a surprise: Java's multidimensional
arrays are actually rigged, being one-dimensional arrays of one-dimensional arrays. Therefore,
pulling n-th element from each of the inner array induces more cache misses, when matrix is large.
-prof perfnorm conveniently highlights that, with >2 cache misses per one benchmark op:
colFirst访
Java
n
-prof perfnorm2
Benchmark Mode Cnt Score Error Units
JMHSample_37_MatrixCopy.colFirst avgt 25 5.306 ± 0.020 ns/op
JMHSample_37_MatrixCopy.colFirst:·CPI avgt 5 0.621 ± 0.011 #/op
JMHSample_37_MatrixCopy.colFirst:·L1-dcache-load-misses avgt 5 2.177 ± 0.044 #/op <-- OOPS
JMHSample_37_MatrixCopy.colFirst:·L1-dcache-loads avgt 5 14.804 ± 0.261 #/op
JMHSample_37_MatrixCopy.colFirst:·LLC-loads avgt 5 2.165 ± 0.091 #/op
JMHSample_37_MatrixCopy.colFirst:·cycles avgt 5 22.272 ± 0.372 #/op
JMHSample_37_MatrixCopy.colFirst:·instructions avgt 5 35.888 ± 1.215 #/op
JMHSample_37_MatrixCopy.rowFirst avgt 25 2.662 ± 0.003 ns/op
JMHSample_37_MatrixCopy.rowFirst:·CPI avgt 5 0.312 ± 0.003 #/op
JMHSample_37_MatrixCopy.rowFirst:·L1-dcache-load-misses avgt 5 0.066 ± 0.001 #/op
JMHSample_37_MatrixCopy.rowFirst:·L1-dcache-loads avgt 5 14.570 ± 0.400 #/op
JMHSample_37_MatrixCopy.rowFirst:·LLC-loads avgt 5 0.002 ± 0.001 #/op
JMHSample_37_MatrixCopy.rowFirst:·cycles avgt 5 11.046 ± 0.343 #/op
JMHSample_37_MatrixCopy.rowFirst:·instructions avgt 5 35.416 ± 1.248 #/op
So, when comparing two different benchmarks, you have to follow up if the difference is caused
by the memory locality issues.
*/
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_37
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + JMHSample_37_CacheAccess.class.getSimpleName() + ".*")
.output("JMHSample_37_CacheAccess.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,177 @@
package com.renchao.jmh;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* desc
*
* @author childe
* @date 2018/10/22 19:47
**/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(5)
public class JMHSample_38_PerInvokeSetup {
/*
* This example highlights the usual mistake in non-steady-state benchmarks.
*
* Suppose we want to test how long it takes to bubble sort an array. Naively,
* we could make the test that populates an array with random (unsorted) values,
* and calls sort on it over and over again:
*
* (non-steady-state benchmarks)
*
*
* 使sort
*/
private void bubbleSort(byte[] b) {
boolean changed = true;
while (changed) {
changed = false;
for (int c = 0; c < b.length - 1; c++) {
if (b[c] > b[c + 1]) {
byte t = b[c];
b[c] = b[c + 1];
b[c + 1] = t;
changed = true;
}
}
}
}
// Could be an implicit State instead, but we are going to use it
// as the dependency in one of the tests below
// 可能是一个隐式状态,但我们将在下面的一个测试中依赖它
@State(Scope.Benchmark)
public static class Data {
@Param({"1", "16", "256"})
int count;
byte[] arr;
@Setup
public void setup() {
arr = new byte[count];
Random random = new Random(1234);
random.nextBytes(arr);
}
}
@Benchmark
public byte[] measureWrong(Data d) {
bubbleSort(d.arr);
return d.arr;
}
/*
* The method above is subtly wrong: it sorts the random array on the first invocation
* only. Every subsequent call will "sort" the already sorted array. With bubble sort,
* that operation would be significantly faster!
*
* This is how we might *try* to measure it right by making a copy in Level.Invocation
* setup. However, this is susceptible to the problems described in Level.Invocation
* Javadocs, READ AND UNDERSTAND THOSE DOCS BEFORE USING THIS APPROACH.
*
*
* "排序"
*
*
* Level.Invocation
* 使Level.Invocation
*/
@State(Scope.Thread)
public static class DataCopy {
byte[] copy;
@Setup(Level.Invocation)
public void setup2(Data d) {
copy = Arrays.copyOf(d.arr, d.arr.length);
}
}
@Benchmark
public byte[] measureNeutral(DataCopy d) {
bubbleSort(d.copy);
return d.copy;
}
/*
* In an overwhelming majority of cases, the only sensible thing to do is to suck up
* the per-invocation setup costs into a benchmark itself. This work well in practice,
* especially when the payload costs dominate the setup costs.
*
*
*
*
*
*/
@Benchmark
public byte[] measureRight(Data d) {
byte[] c = Arrays.copyOf(d.arr, d.arr.length);
bubbleSort(c);
return c;
}
/*
Benchmark (count) Mode Cnt Score Error Units
JMHSample_38_PerInvokeSetup.measureWrong 1 avgt 25 2.408 ± 0.011 ns/op
JMHSample_38_PerInvokeSetup.measureWrong 16 avgt 25 8.286 ± 0.023 ns/op
JMHSample_38_PerInvokeSetup.measureWrong 256 avgt 25 73.405 ± 0.018 ns/op
JMHSample_38_PerInvokeSetup.measureNeutral 1 avgt 25 15.835 ± 0.470 ns/op
JMHSample_38_PerInvokeSetup.measureNeutral 16 avgt 25 112.552 ± 0.787 ns/op
JMHSample_38_PerInvokeSetup.measureNeutral 256 avgt 25 58343.848 ± 991.202 ns/op
JMHSample_38_PerInvokeSetup.measureRight 1 avgt 25 6.075 ± 0.018 ns/op
JMHSample_38_PerInvokeSetup.measureRight 16 avgt 25 102.390 ± 0.676 ns/op
JMHSample_38_PerInvokeSetup.measureRight 256 avgt 25 58812.411 ± 997.951 ns/op
We can clearly see that "measureWrong" provides a very weird result: it "sorts" way too fast.
"measureNeutral" is neither good or bad: while it prepares the data for each invocation correctly,
the timing overheads are clearly visible. These overheads can be overwhelming, depending on
the thread count and/or OS flavor.
"measureWrong"
"measureNeutral"线 / OS
*/
/*
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_38
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + JMHSample_38_PerInvokeSetup.class.getSimpleName() + ".*")
.output("JMHSample_38_PerInvokeSetup.sampleLog")
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,14 @@
package com.renchao.spring;
import com.renchao.spring.bean.Anonymous;
import com.renchao.spring.bean.TestController;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
public class AnnotationUtilsTest {
public static void main(String[] args) {
Anonymous annotation = AnnotationUtils.findAnnotation(TestController.class, Anonymous.class);
System.out.println(annotation);
System.out.println(AnnotatedElementUtils.isAnnotated(TestController.class, Anonymous.class));
}
}

@ -0,0 +1,19 @@
package com.renchao.spring.bean;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 访
*
* @author admin
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}

@ -0,0 +1,5 @@
package com.renchao.spring.bean;
@Anonymous
public class BaseController {
}

@ -0,0 +1,15 @@
package com.renchao.spring.bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Anonymous
public class TestController extends BaseController {
@RequestMapping({"/cc","dd"})
@Anonymous
public String testF() {
return "testFeign.test01()";
}
}

@ -0,0 +1,70 @@
package com.renchao.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import org.hibernate.validator.HibernateValidator;
import org.junit.Test;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.validation.annotation.Validated;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.Set;
public class DateDemo {
public static void main(String[] args) throws JsonProcessingException {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
SimpleModule simpleModule = new SimpleModule()
// .addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(Long.TYPE, ToStringSerializer.instance);
builder.modules(simpleModule);
ObjectMapper build = builder.build();
String str = "{\"id\":22,\"name\":\"aaa\",\"age\":55}";
Bean bean1 = build.readValue(str, Bean.class);
Bean bean = new Bean();
bean.setId(22L);
bean.setName("aaa");
String s = build.writeValueAsString(bean);
System.out.println(s);
}
@Data
static class Bean {
@NotBlank(message = "aabb")
private String name;
@NotNull(message = "唯一标识不能为空")
private Long id;
@NotNull(message = "cc")
private String age;
}
@Test
public void test01() {
Bean bean = new Bean();
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure().failFast(false).buildValidatorFactory().getValidator();
Set<ConstraintViolation<Bean>> validate = validator.validate(bean);
for (ConstraintViolation<Bean> violation : validate) {
System.out.println(violation.getLeafBean());
System.out.println(violation.getMessage());
System.out.println(violation.getMessageTemplate());
System.out.println(violation.getPropertyPath());
System.out.println("======================");
}
}
}

@ -0,0 +1,38 @@
package com.renchao.test;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DemoData {
public static void main(String[] args) {
String filePath = "C:/Users/RENCHAO/Desktop/资料/easyexcel-user1.xls";
List<UserEntity> list = EasyExcel.read(filePath).head(UserEntity.class).sheet().doReadSync();
System.out.println(list);
}
@Test
public void test01() {
String str = "[{\"component\":\"聚酯树脂\",\"content\":\"48%\"},{\"component\":\"乙酸乙酯\",\"content\":\"52%\"}]";
// String str = "ssss";
System.out.println(JSON.isValid(str));
List<Map<String, String>> list = JSON.parseObject(str, new TypeReference<List<Map<String, String>>>() {});
for (Map<String, String> map : list) {
System.out.println(map.get("component") + "::" + map.get("content"));
}
ArrayList<String> strings = new ArrayList<>();
strings.add("cc");
strings.add("dd");
System.out.println(String.join("||", strings));
}
}

@ -0,0 +1,80 @@
package com.renchao.test;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
//@BenchmarkMode(Mode.AverageTime)
//@OutputTimeUnit(TimeUnit.MICROSECONDS)
//@State(Scope.Thread)
public class JMHTest {
/**
*
*/
private final static String DATA = "大白有点菜";
// private List<String> arrayList = new ArrayList<>();
// private List<String> linkedList = new LinkedList<>();
// /**
// * 初始化 ArrayList 和 LinkedList
// */
// @Setup(Level.Iteration)
// public void setUp()
// {
// this.arrayList = new ArrayList<>();
// this.linkedList = new LinkedList<>();
// }
// /**
// * ArrayList的add方法
// * @return
// */
// @Benchmark
// public List<String> arrayListAdd() {
// this.arrayList.add(DATA);
// return arrayList;
// }
// /**
// * LinkedList的add方法
// * @return
// */
// @Benchmark
// public List<String> linkedListAdd() {
// this.linkedList.add(DATA);
// return this.linkedList;
// }
@Benchmark
public int Test() {
int i = 5;
int k = i * 8;
return k;
}
public static void main(String[] args) throws RunnerException {
final Options opts = new OptionsBuilder()
.include(JMHTest.class.getSimpleName())
.forks(1)
// .output("Benchmark1.log")
.build();
new Runner(opts).run();
}
}

@ -0,0 +1,96 @@
package com.renchao.test;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
public class JMHTest2 {
/**
* Most of the time, you need to maintain some state while the benchmark is
* running. Since JMH is heavily used to build concurrent benchmarks, we
* opted for an explicit notion of state-bearing objects.
*
* Below are two state objects. Their class names are not essential, it
* matters they are marked with @State. These objects will be instantiated
* on demand, and reused during the entire benchmark trial.
*
* The important property is that state is always instantiated by one of
* those benchmark threads which will then have the access to that state.
* That means you can initialize the fields as if you do that in worker
* threads (ThreadLocals are yours, etc).
*/
@State(Scope.Benchmark)
public static class BenchmarkState {
volatile double x = Math.PI;
}
@State(Scope.Thread)
public static class ThreadState {
volatile double x = Math.PI;
}
/*
* Benchmark methods can reference the states, and JMH will inject the
* appropriate states while calling these methods. You can have no states at
* all, or have only one state, or have multiple states referenced. This
* makes building multi-threaded benchmark a breeze.
*
* For this exercise, we have two methods.
*/
@Benchmark
public void measureUnshared(ThreadState state) {
// All benchmark threads will call in this method.
//
// However, since ThreadState is the Scope.Thread, each thread
// will have it's own copy of the state, and this benchmark
// will measure unshared case.
state.x++;
}
@Benchmark
public void measureShared(BenchmarkState state) {
// All benchmark threads will call in this method.
//
// Since BenchmarkState is the Scope.Benchmark, all threads
// will share the state instance, and we will end up measuring
// shared case.
state.x++;
}
/**
* ============================== HOW TO RUN THIS TEST: ====================================
*
* You are expected to see the drastic difference in shared and unshared cases,
* because you either contend for single memory location, or not. This effect
* is more articulated on large machines.
*
* You can run this test:
*
* a) Via the command line:
* $ mvn clean install
* $ java -jar target/benchmarks.jar JMHSample_03 -t 4 -f 1
* (we requested 4 threads, single fork; there are also other options, see -h)
*
* b) Via the Java API:
* (see the JMH homepage for possible caveats when running from IDE:
* http://openjdk.java.net/projects/code-tools/jmh/)
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHTest2.class.getSimpleName())
.threads(4)
.forks(1)
.build();
new Runner(opt).run();
}
}

@ -0,0 +1,179 @@
package com.renchao.test;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.renchao.utils.RsaUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Pattern;
public class MyTest {
private static final Pattern pattern = Pattern.compile("[+/]");
public static void main(String[] args) throws JsonProcessingException {
String str = "ee, tt,,cc ";
List<String> split = StrUtil.split(str, ",", true, true);
split.forEach(System.out::println);
}
@Test
public void test01() {
String str = "I:X,II:X.Y,III:X.Y.Z";
String[] split = str.split(",");
HashMap<String, List<String>> map = new HashMap<>();
for (String s : split) {
String[] m = s.split(":");
map.put(m[0], CharSequenceUtil.split(m[1], "."));
}
System.out.println();
}
@Test
public void test03() throws IOException {
String str = "任超";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
byte[] bytes1 = str.getBytes(StandardCharsets.ISO_8859_1);
System.out.println(new String(bytes,StandardCharsets.UTF_8));
System.out.println(new String(bytes1,StandardCharsets.ISO_8859_1));
}
@Test
public void test04() {
String str = "2bce7d71-d60b-4858-a852-15380eba6c84";
String s = RsaUtil.decryptStr(str);
System.out.println(s);
}
@Test
public void test05() {
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG03gR1w6i3E6h6+N9F2///BnRrkzPc7RT4qZKKl2b/rolym0EYl3QZTsIV5oQngT93TLtld7EK5svdwUabX6kzqd8yDDChZXS/E7/FrufN6Hwf9S3O3ZzkhEyd45HmRHV4aNRFsS/NviEZx83D6FR94l0SPnomvPkVqM8UnafnQIDAQAB";
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbTeBHXDqLcTqHr430Xb//8GdGuTM9ztFPipkoqXZv+uiXKbQRiXdBlOwhXmhCeBP3dMu2V3sQrmy93BRptfqTOp3zIMMKFldL8Tv8Wu583ofB/1Lc7dnOSETJ3jkeZEdXho1EWxL82+IRnHzcPoVH3iXRI+eia8+RWozxSdp+dAgMBAAECgYAJjtfqT6LR/HJBQXQ9qrdFIIrjNBRYMrE8CRzCWvgGDEBJmcoU2F+3KW6lj4SGAPqvc4dDuZ0sZAZBSWDy7MmWL+Zz2z44sulxsOsb3DJqIyBSAr5D6mhrRmu7MJA5AGgDHo/2gn+9Cji2JQBHBFe18BzJdr2tIM4uAYTVB6EW8QJBAPCrnHohSDtgLSmHrbORP/cIS8OOF/M3PsYfHZ3cpdrKk2zs1rXAHJq80GlmhSQx8tezx6wt63Cph0reiHbOMRkCQQDTfYqahFR0NTFFfTBfSJKQEqoiRYMnOrjkkOOgFv6cBwYd16pnqTfNISSYkBsOcDO09qiMILW96MoJONCV458lAkEAmMrqueK9X+zMX0xjK9hwOp5Ks2lXrTKKqO+CNwGpTkFD3WhzW8oOnvJ2giPzLSqE2QqrHpW8nrcSTKcBDiQTqQJABORmjGR7P6TrWtwmfk3Ddim4XcqV2hZ1qHPhkBZ4FUvkTFRs0LENZWVa31yWA6N8zrbV90fabGYyJjx2NsFpMQJARtRflzJjWc/49nzu+om41bz9Ngg07/S8Rxe8AlZbSlCxggmp/KUBcoVgNJCa5qGsX2AvTOCXaHngp+YLtHHPBQ==";
RSA rsa = new RSA(privateKey,publicKey);
//获得私钥
System.out.println("获得私钥:" + rsa.getPrivateKey());
System.out.println("获得私钥:" + rsa.getPrivateKeyBase64());
//获得公钥
System.out.println("获得公钥:" + rsa.getPublicKey());
System.out.println("获得公钥:" + rsa.getPublicKeyBase64());
//公钥加密,私钥解密
byte[] encrypt = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
System.out.println("加密后的串:" + rsa.encryptBase64("我是一段测试aaaa",KeyType.PublicKey));
byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
System.out.println("公钥加密,私钥解密:" + new String(decrypt));
//Junit单元测试
//Assert.assertEquals("我是一段测试aaaa", StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8));
//私钥加密,公钥解密
byte[] encrypt2 = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey);
System.out.println("加密后的串:" + rsa.encryptBase64("url=/checkInInfo/reviewResult&token=2bce7d71-d60b-4858-a852-15380eba6c84&timestamp=1574821902392",KeyType.PrivateKey));
byte[] decrypt2 = rsa.decrypt(encrypt2, KeyType.PublicKey);
System.out.println("私钥加密,公钥解密:" + new String(decrypt2));
}
@Test
public void test06() {
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG03gR1w6i3E6h6+N9F2///BnRrkzPc7RT4qZKKl2b/rolym0EYl3QZTsIV5oQngT93TLtld7EK5svdwUabX6kzqd8yDDChZXS/E7/FrufN6Hwf9S3O3ZzkhEyd45HmRHV4aNRFsS/NviEZx83D6FR94l0SPnomvPkVqM8UnafnQIDAQAB";
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbTeBHXDqLcTqHr430Xb//8GdGuTM9ztFPipkoqXZv+uiXKbQRiXdBlOwhXmhCeBP3dMu2V3sQrmy93BRptfqTOp3zIMMKFldL8Tv8Wu583ofB/1Lc7dnOSETJ3jkeZEdXho1EWxL82+IRnHzcPoVH3iXRI+eia8+RWozxSdp+dAgMBAAECgYAJjtfqT6LR/HJBQXQ9qrdFIIrjNBRYMrE8CRzCWvgGDEBJmcoU2F+3KW6lj4SGAPqvc4dDuZ0sZAZBSWDy7MmWL+Zz2z44sulxsOsb3DJqIyBSAr5D6mhrRmu7MJA5AGgDHo/2gn+9Cji2JQBHBFe18BzJdr2tIM4uAYTVB6EW8QJBAPCrnHohSDtgLSmHrbORP/cIS8OOF/M3PsYfHZ3cpdrKk2zs1rXAHJq80GlmhSQx8tezx6wt63Cph0reiHbOMRkCQQDTfYqahFR0NTFFfTBfSJKQEqoiRYMnOrjkkOOgFv6cBwYd16pnqTfNISSYkBsOcDO09qiMILW96MoJONCV458lAkEAmMrqueK9X+zMX0xjK9hwOp5Ks2lXrTKKqO+CNwGpTkFD3WhzW8oOnvJ2giPzLSqE2QqrHpW8nrcSTKcBDiQTqQJABORmjGR7P6TrWtwmfk3Ddim4XcqV2hZ1qHPhkBZ4FUvkTFRs0LENZWVa31yWA6N8zrbV90fabGYyJjx2NsFpMQJARtRflzJjWc/49nzu+om41bz9Ngg07/S8Rxe8AlZbSlCxggmp/KUBcoVgNJCa5qGsX2AvTOCXaHngp+YLtHHPBQ==";
RSA rsa = new RSA(null,publicKey);
String str = "mlVdU379GcmXAFJvtdJ5rhoLrTOg89/efKmQvCtcYnEFUdZYuivURy0T62S0jN+KCKJ70LpfX7uoBMitBixAK8sUNq9YF9GF4GmnhSJHHklsgEujz+ULwPIG3kbhYpjKCl0RQXwdjyz0htNgLn6MR6M7JQ2fAbtR6nDL1Z2W8Ig=";
String decrypt = rsa.decryptStr(str, KeyType.PublicKey);
System.out.println(decrypt);
}
/**
*
*/
@Test
public void test07() throws UnsupportedEncodingException {
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG03gR1w6i3E6h6+N9F2///BnRrkzPc7RT4qZKKl2b/rolym0EYl3QZTsIV5oQngT93TLtld7EK5svdwUabX6kzqd8yDDChZXS/E7/FrufN6Hwf9S3O3ZzkhEyd45HmRHV4aNRFsS/NviEZx83D6FR94l0SPnomvPkVqM8UnafnQIDAQAB";
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbTeBHXDqLcTqHr430Xb//8GdGuTM9ztFPipkoqXZv+uiXKbQRiXdBlOwhXmhCeBP3dMu2V3sQrmy93BRptfqTOp3zIMMKFldL8Tv8Wu583ofB/1Lc7dnOSETJ3jkeZEdXho1EWxL82+IRnHzcPoVH3iXRI+eia8+RWozxSdp+dAgMBAAECgYAJjtfqT6LR/HJBQXQ9qrdFIIrjNBRYMrE8CRzCWvgGDEBJmcoU2F+3KW6lj4SGAPqvc4dDuZ0sZAZBSWDy7MmWL+Zz2z44sulxsOsb3DJqIyBSAr5D6mhrRmu7MJA5AGgDHo/2gn+9Cji2JQBHBFe18BzJdr2tIM4uAYTVB6EW8QJBAPCrnHohSDtgLSmHrbORP/cIS8OOF/M3PsYfHZ3cpdrKk2zs1rXAHJq80GlmhSQx8tezx6wt63Cph0reiHbOMRkCQQDTfYqahFR0NTFFfTBfSJKQEqoiRYMnOrjkkOOgFv6cBwYd16pnqTfNISSYkBsOcDO09qiMILW96MoJONCV458lAkEAmMrqueK9X+zMX0xjK9hwOp5Ks2lXrTKKqO+CNwGpTkFD3WhzW8oOnvJ2giPzLSqE2QqrHpW8nrcSTKcBDiQTqQJABORmjGR7P6TrWtwmfk3Ddim4XcqV2hZ1qHPhkBZ4FUvkTFRs0LENZWVa31yWA6N8zrbV90fabGYyJjx2NsFpMQJARtRflzJjWc/49nzu+om41bz9Ngg07/S8Rxe8AlZbSlCxggmp/KUBcoVgNJCa5qGsX2AvTOCXaHngp+YLtHHPBQ==";
RSA rsa = new RSA(privateKey,null);
String str = "url=/checkInInfo/reviewResult&token=5bce7d71-d60b-4858-a852-15380eba6c84&timestamp=1681440129945";
String base64 = rsa.encryptBase64(str, KeyType.PrivateKey);
System.out.println(base64);
System.out.println(URLEncoder.encode(base64,"UTF-8"));
System.out.println("==========PublicKey解密=============");
RSA rsa2 = new RSA(null, publicKey);
try {
System.out.println(rsa2.decryptStr(base64 + "ss", KeyType.PublicKey));
} catch (CryptoException e) {
System.out.println("发生异常===================" + e);
}
}
@Test
public void test() {
List<String> list = new ArrayList<>();
list.add("聚酯树脂");
list.add("聚酯树脂33");
list.add("4,4'-(1-甲基亚乙基)双苯酚与(氯甲基)环氧乙烷的聚合物(平均分子量≤700)");
System.out.println(JSONUtil.toJsonStr(list));
System.out.println(this.getClass().getResource("/"));
}
@Test
public void test00() throws IOException {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("template/declarationInformationExport.docx");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
byte[] byteArray = outputStream.toByteArray();
long l = System.currentTimeMillis();
for (int i = 0; i < 50000; i++) {
// InputStream inputStream2 = getClass().getClassLoader().getResourceAsStream("template/declarationInformationExport.docx");
// InputStream inputStream2 = new FileInputStream("C:\\Users\\RENCHAO\\IdeaProjects\\Test\\MyMaven\\src\\main\\resources\\template\\declarationInformationExport.docx");
InputStream inputStream2 = new ByteArrayInputStream(byteArray);
byte[] bytes = new byte[1024 * 1024];
inputStream2.read(bytes);
}
System.out.println(System.currentTimeMillis() - l);
}
@Test
public void test08() {
System.out.println(new Date());
System.out.println(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));
System.out.println(TimeZone.getDefault());
}
}

@ -0,0 +1,38 @@
package com.renchao.test;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
@ExcelProperty(value = "姓名")
private String name;
@ExcelProperty(value = "年龄")
private int age;
@ExcelProperty(value = "操作时间")
private Date time;
public static void main(String[] args) {
List<UserEntity> dataList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
UserEntity userEntity = new UserEntity();
userEntity.setName("张三" + i);
userEntity.setAge(20 + i);
userEntity.setTime(new Date(System.currentTimeMillis() + i));
dataList.add(userEntity);
}
EasyExcel.write("C:/Users/RENCHAO/Desktop/资料/easyexcel-user1.xls", UserEntity.class).sheet("用户信息").doWrite(dataList);
}
}

@ -0,0 +1,123 @@
package com.renchao.test;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import lombok.Data;
import org.hibernate.validator.HibernateValidator;
public class ValidationUtil {
/**
* failFast (true)
*/
private static final Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
/**
*
*
* @param t bean
* @param groups
* @return ValidResult
*/
public static <T> ValidResult validateBean(T t,Class<?>...groups) {
ValidResult result = new ValidResult();
Set<ConstraintViolation<T>> violationSet = validator.validate(t,groups);
boolean hasError = violationSet != null && violationSet.size() > 0;
result.setHasErrors(hasError);
if (hasError) {
for (ConstraintViolation<T> violation : violationSet) {
result.addError(violation.getPropertyPath().toString(), violation.getMessage());
}
}
return result;
}
/**
* bean
*
* @param obj bean
* @param propertyName
* @return ValidResult
*/
public static <T> ValidResult validateProperty(T obj, String propertyName) {
ValidResult result = new ValidResult();
Set<ConstraintViolation<T>> violationSet = validator.validateProperty(obj, propertyName);
boolean hasError = violationSet != null && violationSet.size() > 0;
result.setHasErrors(hasError);
if (hasError) {
for (ConstraintViolation<T> violation : violationSet) {
result.addError(propertyName, violation.getMessage());
}
}
return result;
}
/**
*
*/
@Data
static class ValidResult {
/**
*
*/
private boolean hasErrors;
/**
*
*/
private List<ErrorMessage> errors;
public ValidResult() {
this.errors = new ArrayList<>();
}
public boolean hasErrors() {
return hasErrors;
}
public void setHasErrors(boolean hasErrors) {
this.hasErrors = hasErrors;
}
/**
*
* @return
*/
public List<ErrorMessage> getAllErrors() {
return errors;
}
/**
*
* @return
*/
public String getErrors(){
StringBuilder sb = new StringBuilder();
for (ErrorMessage error : errors) {
sb.append(error.getPropertyPath()).append(":").append(error.getMessage()).append(" \n");
}
return sb.toString();
}
public void addError(String propertyName, String message) {
this.errors.add(new ErrorMessage(propertyName, message));
}
}
@Data
static class ErrorMessage {
private String propertyPath;
private String message;
public ErrorMessage() {
}
public ErrorMessage(String propertyPath, String message) {
this.propertyPath = propertyPath;
this.message = message;
}
}
}

@ -0,0 +1,15 @@
package com.renchao.utils;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
public class RsaUtil {
private static final RSA PUB_RSA = new RSA(null, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMdrstRnZe65DiLQtGUuA33JKdwf4P4oBSd0itbUYmn/8N4Z9kVKap/yLZhXU8JRoI7yJLizR0iszlllbrRor+HBhB56NaHnZ1zTshELII/QXLCbqfevVDOcfvMs5OGa7pThxn3r08H7RCdko9xVWYDZvf3xJzrGe9Zj//zbe5ywIDAQAB");
public static String decryptStr(String content) {
return PUB_RSA.decryptStr(content, KeyType.PublicKey);
}
}

@ -0,0 +1,226 @@
package com.renchao.word;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.CTGroup;
import com.microsoft.schemas.vml.CTShape;
import com.microsoft.schemas.vml.CTShapetype;
import com.microsoft.schemas.vml.CTTextPath;
import com.microsoft.schemas.vml.STExt;
import com.microsoft.schemas.vml.STTrueFalse;
import org.apache.poi.util.IOUtils;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.junit.Test;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class XWPFDocumentDemo {
private static byte[] b = null;
public static void main(String[] args) throws IOException {
// File file = new File("C:\\Users\\RENCHAO\\Desktop\\新建文件夹\\allReviewInfoTemplate.docx");
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\RENCHAO\\Desktop\\新建文件夹\\abcd.zip");
// b 22530
long l = System.currentTimeMillis();
ZipOutputStream out = new ZipOutputStream(outputStream);
for (int i = 0; i < 1000; i++) {
extracted(out, i);
}
out.close();
outputStream.close();
System.out.println(System.currentTimeMillis() - l);
}
private static byte[] getByte() throws IOException {
if (b != null) {
return b;
}
InputStream is = new FileInputStream("C:\\Users\\RENCHAO\\Desktop\\aaa.docx");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
b = outputStream.toByteArray();
return b;
}
private static void extracted(ZipOutputStream out, int i) throws IOException {
XWPFDocument doc = new XWPFDocument(new FileInputStream("C:\\Users\\RENCHAO\\Desktop\\aaa.docx"));
// XWPFDocument doc = new XWPFDocument(new ByteArrayInputStream(getByte()));
List<XWPFTable> tables = doc.getTables();
List<XWPFTableCell> cells;
List<XWPFTableRow> rows;
// 委托单位
rows = tables.get(0).getRows();
cells = rows.get(0).getTableCells();
cells.get(1).setText("My测试的委托单位");
// 违规货物信息
rows = tables.get(1).getRows();
cells = rows.get(0).getTableCells();
cells.get(1).setText("inOutType");
cells.get(3).setText("goodsName");
cells.get(5).setText("goodsId");
cells = rows.get(1).getTableCells();
cells.get(1).setText("unNo");
cells.get(3).setText("composition");
cells.get(5).setText("transportNameCn");
cells = rows.get(2).getTableCells();
cells.get(1).setText("dangerType");
cells.get(3).setText("packageClass");
cells.get(5).setText("chemicalName");
cells = rows.get(3).getTableCells();
cells.get(1).setText("remarks");
// 危规货物属性
rows = tables.get(2).getRows();
cells = rows.get(0).getTableCells();
cells.get(1).setText("hsCode");
cells.get(3).setText("ciqName");
cells.get(5).setText("ciqNo");
cells = rows.get(1).getTableCells();
cells.get(1).setText("goodsAttr");
cells.get(3).setText("packSign");
// 输出到本地目录
// FileOutputStream fos = new FileOutputStream("C:\\Users\\RENCHAO\\Desktop\\新建文件夹\\aaa\\AAA.docx");
// fos.flush();
// fos.close();
out.putNextEntry(new ZipEntry("aaaaa" + i + ".docx"));
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
doc.write(arrayOutputStream);
out.write(arrayOutputStream.toByteArray());
doc.close();
}
@Test
public void test02() throws IOException {
XWPFDocument doc = new XWPFDocument(new FileInputStream("C:\\Users\\RENCHAO\\Desktop\\DeclarationInformationExport.docx"));
waterMarkDocxDocument(doc, "CCIC 2023-06");
doc.write(new FileOutputStream("C:\\Users\\RENCHAO\\Desktop\\DIE.docx"));
doc.close();
}
/**
* <br />
* {@link org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy#createWatermark(String)}
*
* @param doc docx
* @param waterMark
*/
private void waterMarkDocxDocument(XWPFDocument doc, String waterMark) {
// 获取文档的所有页眉,如果文档没有页眉,则新建一个默认页眉
List<XWPFHeader> headerList = new ArrayList<>(doc.getHeaderList());
if (headerList.isEmpty()) {
headerList.add(doc.createHeader(HeaderFooterType.DEFAULT));
}
// 遍历所有的header这里包含所有的分页
for (XWPFHeader header : headerList) {
int size = header.getParagraphs().size();
if (size == 0) {
header.createParagraph();
}
XWPFParagraph paragraph = header.getParagraphArray(0);
CTP ctp = paragraph.getCTP();
byte[] rsidR = doc.getDocument().getBody().getPArray(0).getRsidR();
byte[] rsidRDefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
ctp.setRsidP(rsidR);
ctp.setRsidRDefault(rsidRDefault);
CTPPr ppr = ctp.addNewPPr();
ppr.addNewPStyle().setVal("Header");
// 开始加水印
CTR ctr = ctp.addNewR();
CTRPr ctrpr = ctr.addNewRPr();
ctrpr.addNewNoProof();
CTGroup group = CTGroup.Factory.newInstance();
CTShapetype shapeType = group.addNewShapetype();
CTTextPath shapeTypeTextPath = shapeType.addNewTextpath();
shapeTypeTextPath.setOn(STTrueFalse.T);
shapeTypeTextPath.setFitshape(STTrueFalse.T);
CTLock lock = shapeType.addNewLock();
lock.setExt(STExt.VIEW);
CTShape shape = group.addNewShape();
shape.setId("PowerPlusWaterMarkObject");
shape.setSpid("_x0000_s102");
shape.setType("#_x0000_t136");
// 设置形状样式(旋转,位置,相对路径等参数)
shape.setStyle(getShapeStyle());
shape.setFillcolor("#d8d8d8");
// 字体设置为实心
shape.setStroked(STTrueFalse.FALSE);
// 绘制文本的路径
CTTextPath shapeTextPath = shape.addNewTextpath();
// 设置文本字体与大小
shapeTextPath.setStyle("font-family:Arial;font-size:1pt");
shapeTextPath.setString(waterMark);
CTPicture pict = ctr.addNewPict();
pict.set(group);
}
}
/**
* Shape
*/
private String getShapeStyle() {
// 文本path绘制的定位方式
return "position: " + "absolute" +
";margin-top: " + 0 +
";width: " + "415pt" +
";height: " + "207.5pt" +
";z-index: " + "-251654144" +
";mso-wrap-edited: " + "f" +
";mso-position-horizontal: " + "center" +
";mso-position-horizontal-relative: " + "margin" +
";mso-position-vertical-relative: " + "margin" +
";mso-position-vertical: " + "center" +
";rotation: " + 315;
}
}

@ -0,0 +1,550 @@
package com.jiuyv.business.domain;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.jiuyv.common.annotation.Excel;
import com.jiuyv.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 货物申报信息对象 tbl_goods_declare_info
*
* @author jiuyv
* @date 2023-02-07
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class TblGoodsDeclareInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 物料编号
*/
@Excel(name = "物料编号")
@NotBlank(message = "物料编号不能为空")
private String goodsId;
/**
* 版本
*/
@Excel(name = "版本")
private Long version;
/**
* 委托单位ID
*/
@Excel(name = "委托单位ID")
@NotBlank(message = "委托单位ID不能为空")
private String delegateId;
/**
* 委托单位名称
*/
@Excel(name = "委托单位名称")
@NotBlank(message = "委托单位名称不能为空")
private String delegateName;
/**
* 货物名称
*/
@Excel(name = "货物名称")
@NotBlank(message = "货物名称不能为空")
private String goodsName;
/**
* 出入境标识
*/
@Excel(name = "出入境标识")
@NotBlank(message = "出入境标识不能为空")
private String inOutType;
/**
* $column.columnComment
*/
@Excel(name = "联合国编号")
@NotBlank(message = "UN编号不能为空")
private String unNo;
/**
* 成分含量
*/
@Excel(name = "成分含量")
@NotBlank(message = "成分含量不能为空")
private String composition;
/**
* 正式运输名称
*/
@Excel(name = "正式运输名称")
private String transportNameCn;
/**
* 危险类别
*/
@Excel(name = "危险类别")
private String dangerType;
/**
* 包装类别
*/
@Excel(name = "包装类别")
private String packageClass;
/**
* 关联危险品货物ID
*/
@Excel(name = "关联危险品货物ID")
private Long goodsInfoId;
/**
* 化学品名称
*/
@Excel(name = "化学品名称")
@NotBlank(message = "化学品名称不能为空")
private String chemicalName;
/**
* 关联危化品目录ID
*/
@Excel(name = "关联危化品目录ID")
private Long catalogueInfoId;
/**
* 备注
*/
@Excel(name = "备注")
private String remarks;
/**
* HS编码
*/
@Excel(name = "HS编码")
@NotBlank(message = "HS编码不能为空")
private String hsCode;
/**
* 检验检疫名称
*/
@Excel(name = "检验检疫名称")
private String ciqName;
/**
* CIQ代码
*/
@Excel(name = "CIQ代码")
private String ciqNo;
/**
* 关联CIQ危险化学品ID
*/
@Excel(name = "关联CIQ危险化学品ID")
@NotNull(message = "关联CIQ危险化学品ID不能为空")
private Long ciqGoodsInfoId;
/**
* 货物属性
*/
@Excel(name = "货物属性")
private String goodsAttr;
/**
* 包装UN标记
*/
@Excel(name = "包装UN标记")
private String packSign;
/**
* 状态0正常 1废除
*/
@Excel(name = "状态", readConverterExp = "0=正常,1=废除")
private String status;
/**
* 数据状态0存在 2删除
*/
@Excel(name = "数据状态", readConverterExp = "0=存在,2=删除")
private String dataStatus;
/**
* rectoken
*/
@Excel(name = "rectoken")
private String recToken;
/**
* 创建人id
*/
@Excel(name = "创建人id")
private Long createById;
/**
* 修改人id
*/
@Excel(name = "修改人id")
private Long updateById;
/**
* $column.columnComment
*/
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
private String rsv1;
/**
* $column.columnComment
*/
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
private String rsv2;
/**
* $column.columnComment
*/
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
private String rsv3;
/**
* 关联分类鉴定信息ID
*/
@Excel(name = "关联分类鉴定信息ID")
private Long dangerIdentifyInfoId;
/**
* 货代公司ID
*/
@Excel(name = "货代公司ID")
private Long agentId;
/**
* 货代公司
*/
@Excel(name = "货代公司")
private String agentName;
private String recTokenEt;
/**
* 随附文件
*/
private List<MultipartFile> files;
/**
* 文件信息
*/
private List<TblAttachFileInfo> attachFileInfos;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setGoodsId(String goodsId) {
this.goodsId = goodsId;
}
public String getGoodsId() {
return goodsId;
}
public void setVersion(Long version) {
this.version = version;
}
public Long getVersion() {
return version;
}
public void setDelegateId(String delegateId) {
this.delegateId = delegateId;
}
public String getDelegateId() {
return delegateId;
}
public void setDelegateName(String delegateName) {
this.delegateName = delegateName;
}
public String getDelegateName() {
return delegateName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public String getGoodsName() {
return goodsName;
}
public void setInOutType(String inOutType) {
this.inOutType = inOutType;
}
public String getInOutType() {
return inOutType;
}
public void setUnNo(String unNo) {
this.unNo = unNo;
}
public String getUnNo() {
return unNo;
}
public void setComposition(String composition) {
this.composition = composition;
}
public String getComposition() {
return composition;
}
public void setTransportNameCn(String transportNameCn) {
this.transportNameCn = transportNameCn;
}
public String getTransportNameCn() {
return transportNameCn;
}
public void setDangerType(String dangerType) {
this.dangerType = dangerType;
}
public String getDangerType() {
return dangerType;
}
public void setPackageClass(String packageClass) {
this.packageClass = packageClass;
}
public String getPackageClass() {
return packageClass;
}
public void setGoodsInfoId(Long goodsInfoId) {
this.goodsInfoId = goodsInfoId;
}
public Long getGoodsInfoId() {
return goodsInfoId;
}
public void setChemicalName(String chemicalName) {
this.chemicalName = chemicalName;
}
public String getChemicalName() {
return chemicalName;
}
public void setCatalogueInfoId(Long catalogueInfoId) {
this.catalogueInfoId = catalogueInfoId;
}
public Long getCatalogueInfoId() {
return catalogueInfoId;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
public String getRemarks() {
return remarks;
}
public void setHsCode(String hsCode) {
this.hsCode = hsCode;
}
public String getHsCode() {
return hsCode;
}
public void setCiqName(String ciqName) {
this.ciqName = ciqName;
}
public String getCiqName() {
return ciqName;
}
public void setCiqNo(String ciqNo) {
this.ciqNo = ciqNo;
}
public String getCiqNo() {
return ciqNo;
}
public void setCiqGoodsInfoId(Long ciqGoodsInfoId) {
this.ciqGoodsInfoId = ciqGoodsInfoId;
}
public Long getCiqGoodsInfoId() {
return ciqGoodsInfoId;
}
public void setGoodsAttr(String goodsAttr) {
this.goodsAttr = goodsAttr;
}
public String getGoodsAttr() {
return goodsAttr;
}
public void setPackSign(String packSign) {
this.packSign = packSign;
}
public String getPackSign() {
return packSign;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setDataStatus(String dataStatus) {
this.dataStatus = dataStatus;
}
public String getDataStatus() {
return dataStatus;
}
public void setRecToken(String recToken) {
this.recToken = recToken;
}
public String getRecToken() {
return recToken;
}
public void setCreateById(Long createById) {
this.createById = createById;
}
public Long getCreateById() {
return createById;
}
public void setUpdateById(Long updateById) {
this.updateById = updateById;
}
public Long getUpdateById() {
return updateById;
}
public void setRsv1(String rsv1) {
this.rsv1 = rsv1;
}
public String getRsv1() {
return rsv1;
}
public void setRsv2(String rsv2) {
this.rsv2 = rsv2;
}
public String getRsv2() {
return rsv2;
}
public void setRsv3(String rsv3) {
this.rsv3 = rsv3;
}
public String getRsv3() {
return rsv3;
}
public void setDangerIdentifyInfoId(Long dangerIdentifyInfoId) {
this.dangerIdentifyInfoId = dangerIdentifyInfoId;
}
public Long getDangerIdentifyInfoId() {
return dangerIdentifyInfoId;
}
public void setAgentId(Long agentId) {
this.agentId = agentId;
}
public Long getAgentId() {
return agentId;
}
public String getRecTokenEt() {
return recTokenEt;
}
public void setRecTokenEt(String recTokenEt) {
this.recTokenEt = recTokenEt;
}
public List<MultipartFile> getFiles() {
return files;
}
public void setFiles(List<MultipartFile> files) {
this.files = files;
}
public List<TblAttachFileInfo> getAttachFileInfos() {
return attachFileInfos;
}
public void setAttachFileInfos(List<TblAttachFileInfo> attachFileInfos) {
this.attachFileInfos = attachFileInfos;
}
public String getAgentName() {
return agentName;
}
public void setAgentName(String agentName) {
this.agentName = agentName;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("id", getId())
.append("goodsId", getGoodsId()).append("version", getVersion()).append("delegateId", getDelegateId())
.append("delegateName", getDelegateName()).append("goodsName", getGoodsName())
.append("inOutType", getInOutType()).append("unNo", getUnNo()).append("composition", getComposition())
.append("transportNameCn", getTransportNameCn()).append("dangerType", getDangerType())
.append("packageClass", getPackageClass()).append("goodsInfoId", getGoodsInfoId())
.append("chemicalName", getChemicalName()).append("catalogueInfoId", getCatalogueInfoId())
.append("remarks", getRemarks()).append("hsCode", getHsCode()).append("ciqName", getCiqName())
.append("ciqNo", getCiqNo()).append("ciqGoodsInfoId", getCiqGoodsInfoId())
.append("goodsAttr", getGoodsAttr()).append("packSign", getPackSign()).append("status", getStatus())
.append("dataStatus", getDataStatus()).append("recToken", getRecToken())
.append("createById", getCreateById()).append("createBy", getCreateBy())
.append("createTime", getCreateTime()).append("updateById", getUpdateById())
.append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).append("rsv1", getRsv1())
.append("rsv2", getRsv2()).append("rsv3", getRsv3())
.append("dangerIdentifyInfoId", getDangerIdentifyInfoId()).append("agentId", getAgentId()).toString();
}
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<!--
name:指定kbase的名称可以任意但是需要唯一
packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
default:指定当前kbase是否为默认
-->
<kbase name="myKbase1" packages="rules" default="true">
<!--
name:指定ksession的名称可以任意但需要唯一
default:指定当前session是否为默认
-->
<ksession name="ksession-rule" default="true"/>
</kbase>
</kmodule>

@ -0,0 +1,137 @@
// 图书优惠规则
package book.discount
import com.renchao.drools.Order
import java.util.List
import java.util.Set
import java.lang.Integer
import java.util.ArrayList
import org.springframework.util.CollectionUtils
// 规则一所购图书总价在100元以下的没有优惠
rule "book_discount_1"
when
$order: Order(originalPrice < 100) // 匹配模式到规则引擎中工作内存查找Order对象命名为$order
$str: String(true)
then
$order.setRealPrice($order.getOriginalPrice());
System.out.println("成功匹配到规则一所购图书总价在100元以下无优惠");
System.out.println(">>>>>" + $str);
List<String> list = $order.getStringList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String s : list) {
if (s.equals("bbb")){
System.out.println(s);
}
}
insert(list);
end
// 规则二所购图书总价在100~200的优惠20元
rule "book_discount_2"
when
$order: Order(originalPrice >= 100 && originalPrice < 200)
then
Double originalPrice = $order.getOriginalPrice();
System.out.println(">>>>>>>>" + originalPrice);
$order.setRealPrice($order.getOriginalPrice() - 20);
System.out.println("成功匹配到规则二所购图书总价在100~200元之间");
end
// 规则三所购图书总价在200~300元的优惠50元
rule "book_discount_3"
when
$order: Order(originalPrice >= 200 && originalPrice < 300)
then
$order.setRealPrice($order.getOriginalPrice() - 50);
System.out.println("成功匹配到规则三所购图书总价在200~300元之间");
end
// 规则四所购图书总价在300元及以上的优惠100元
rule "book_discount_4"
when
$order: Order(originalPrice >= 300)
then
$order.setRealPrice($order.getOriginalPrice() - 100);
System.out.println("成功匹配到规则四所购图书总价在300元及以上");
end
// 规则5所购图书总价在300元及以上的优惠100元
rule "book_discount_5"
when
$list: List(size > 0)
then
String join = String.join(",",$list);
System.out.println("list不是空的。。。。》》》》》" + join);
end
// 规则6
rule "book_discount_6"
when
$list: List(CollectionUtils.isEmpty($list))
then
System.out.println("list是空的。。。。》》》》》hehe");
end
// 规则7
rule "book_discount_7"
when
$set: Set(true)
$list: List(true)
$i: Integer($i > 6)
then
$set.add($i * 2);
$list.add($i);
end
// 规则8
rule "book_discount_8"
when
$list: List(size > 1)
then
System.out.println($list);
List<String> list = new ArrayList<>();
insert(list);
end
// 规则9
rule "book_discount_9"
salience 10
activation-group "test"
// no-loop true
when
$order: Order(stringList == null/* && stringList.size() == 0*/)
then
System.out.println("999 Order的list是空的。。。。》》》》》");
// update($order)
end
// 规则9
rule "book_discount_10"
salience 20
activation-group "test"
no-loop true
when
$order: Order(stringList != null && stringList.size() == 0)
then
System.out.println("10 10 Order的list是空的。。。。》》》》》");
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
$order.setStringList(list);
update($order)
end
// 规则11
rule "book_discount_11"
when
$order: Order(stringList != null && stringList.size() == 2)
then
System.out.println("11 11 Order的list是空的。。。。》》》》》");
// update($order)
end

@ -0,0 +1,70 @@
package com.renchao;
import org.junit.Test;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RSADemo {
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
System.out.println(publicKey.getFormat());
PrivateKey privateKey = keyPair.getPrivate();
// 加密消息
String message = "Hello RSA";
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedMessage = cipher.doFinal(message.getBytes());
System.out.println("Encrypted message: " + Base64.getEncoder().encodeToString(encryptedMessage));
// 解密密文
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessage = cipher.doFinal(encryptedMessage);
System.out.println("Decrypted message: " + new String(decryptedMessage));
}
@Test
public void test01() throws Exception {
// String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG03gR1w6i3E6h6+N9F2///BnRrkzPc7RT4qZKKl2b/rolym0EYl3QZTsIV5oQngT93TLtld7EK5svdwUabX6kzqd8yDDChZXS/E7/FrufN6Hwf9S3O3ZzkhEyd45HmRHV4aNRFsS/NviEZx83D6FR94l0SPnomvPkVqM8UnafnQIDAQAB";
String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUAPS4EiEkyKAay4dRY7hWuyTSewj3X1g9NXj6832Eup0VE+xxGfsDiU5xlZBenFcLT8nn88q3mYit5DowuwxTCmem2TIAfkxdAnZ4vm7ndVbugQTu3TDB5R7LIGRjNF62lfwzYc7ywJFHVH/7dVfh4/uaijjQeDhznlBxM57NgwIDAQAB";
String privateKeyStr = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbTeBHXDqLcTqHr430Xb//8GdGuTM9ztFPipkoqXZv+uiXKbQRiXdBlOwhXmhCeBP3dMu2V3sQrmy93BRptfqTOp3zIMMKFldL8Tv8Wu583ofB/1Lc7dnOSETJ3jkeZEdXho1EWxL82+IRnHzcPoVH3iXRI+eia8+RWozxSdp+dAgMBAAECgYAJjtfqT6LR/HJBQXQ9qrdFIIrjNBRYMrE8CRzCWvgGDEBJmcoU2F+3KW6lj4SGAPqvc4dDuZ0sZAZBSWDy7MmWL+Zz2z44sulxsOsb3DJqIyBSAr5D6mhrRmu7MJA5AGgDHo/2gn+9Cji2JQBHBFe18BzJdr2tIM4uAYTVB6EW8QJBAPCrnHohSDtgLSmHrbORP/cIS8OOF/M3PsYfHZ3cpdrKk2zs1rXAHJq80GlmhSQx8tezx6wt63Cph0reiHbOMRkCQQDTfYqahFR0NTFFfTBfSJKQEqoiRYMnOrjkkOOgFv6cBwYd16pnqTfNISSYkBsOcDO09qiMILW96MoJONCV458lAkEAmMrqueK9X+zMX0xjK9hwOp5Ks2lXrTKKqO+CNwGpTkFD3WhzW8oOnvJ2giPzLSqE2QqrHpW8nrcSTKcBDiQTqQJABORmjGR7P6TrWtwmfk3Ddim4XcqV2hZ1qHPhkBZ4FUvkTFRs0LENZWVa31yWA6N8zrbV90fabGYyJjx2NsFpMQJARtRflzJjWc/49nzu+om41bz9Ngg07/S8Rxe8AlZbSlCxggmp/KUBcoVgNJCa5qGsX2AvTOCXaHngp+YLtHHPBQ==";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Cipher rsa = Cipher.getInstance("RSA");
// 加密 Hello
KeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
PublicKey publicKey = keyFactory.generatePublic(keySpec);
System.out.println(publicKey);
System.out.println(System.currentTimeMillis());
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
String str = "Admin1234," + System.currentTimeMillis();
byte[] bytes = rsa.doFinal(str.getBytes(StandardCharsets.UTF_8));
String s = Base64.getEncoder().encodeToString(bytes);
System.out.println(s);
// 解密
// KeySpec keySpec2 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr));
// PrivateKey privateKey = keyFactory.generatePrivate(keySpec2);
// rsa.init(Cipher.DECRYPT_MODE, privateKey);
// byte[] bytes1 = rsa.doFinal(Base64.getDecoder().decode(s));
// System.out.println("解密后:" + new String(bytes1, StandardCharsets.UTF_8));
}
}

@ -0,0 +1,141 @@
package com.renchao;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExDemo {
public static void main(String[] args) {
String str = "2.3+5.1+8";
String[] split = str.split("\\+");
System.out.println(Arrays.toString(split));
}
@Test
public void test() {
String str = "2.3/5.1+8Dd./";
System.out.println(str.replaceAll("[+/a-zA-Z]", ""));
}
@Test
public void test02() {
// String str = "3UN1263Ⅲ";
// String str = "2.2/UN1956/P200";
// String str = "6.1/3/8UN2740";
String str = "2.38UN1079I";
// String str = "正式运输名称丁醇类联合国编号UN1120危险货物类别3包装类II海洋污染物否。";
// String str = "正式运输名称四氯化硅联合国编号UN1818危险货物类别2.38包装类II海洋污染物否。";
// String str = "正式运输名称四氯化硅联合国编号UN1818危险货物类别8包装类II海洋污染物否。";
// Pattern pattern = Pattern.compile("类别[:]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?)([(]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?))[)])?)");
// Pattern pattern = Pattern.compile("(\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?)([(]((\\d(\\.\\d)?[+/])*(\\d(\\.\\d)?))[)])?");
// Pattern pattern = Pattern.compile("([Uu][Nn])(\\d{4})");
// Pattern pattern = Pattern.compile("[IⅡⅢ]{1,3}");
Pattern pattern = Pattern.compile("[,:;/](I{1,3}|([ⅠⅡⅢ]))|\\d{4}[,:;/]([123])");
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("0位置" + matcher.group());
System.out.println("1位置" + matcher.group(1));
System.out.println("2位置" + matcher.group(2));
System.out.println("3位置" + matcher.group(3));
System.out.println("4位置" + matcher.group(4));
System.out.println("5位置" + matcher.group(5));
System.out.println("6位置" + matcher.group(6));
System.out.println("7位置" + matcher.group(7));
System.out.println("8位置" + matcher.group(8));
}
}
@Test
public void test04() {
String str = "url=/checkInInfo/reviewResult&token=2bce7d71-d60b-4858-a852-15380eba6c84&timestamp=1574821902392";
Pattern pattern = Pattern.compile("[0-9a-f]+(-[0-9a-f]+){4}");
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("0位置" + matcher.group());
// System.out.println("1位置" + matcher.group(1));
}
}
@Test
public void test05() {
// String str = "乙酸乙酯30-50%2-乙基-2-(羟甲基)-1,3-丙二醇与1,3-二异氰酸根合甲基苯和2,2'-氧二乙醇的聚合物1-10%";
// String str = "2-乙基-2-(羟甲基)-1,3-丙二醇与1,3-二异氰酸根合甲基苯和2,2'-氧二乙醇的聚合物25-40%甲乙酮10-20%乙酸乙酯10-20%2-乙基-2-(羟甲基)-1,3-丙二醇与1,3-二异氰酸根合甲基苯和2,2'-氧二乙醇的聚合物25-40%";
String str = "乙酸乙酯30-50%甲乙酮10-20%4,4'-(1-甲基亚乙基二苯酚与2,2'-[(1-甲基亚乙基)二(4,1-亚苯基氧亚甲基)]二环氧乙烷的聚合物2.5-10%";
// Pattern pattern = Pattern.compile("([^%]+)%"); (?=[0-9>≥<<≤-]+%)
// Pattern pattern = Pattern.compile("([^%]+)([0-9>≥<<≤-]+%)");
// Pattern pattern = Pattern.compile("(-?\\d[,-]?\\d?\\D+)([0-9>≥<<≤-]+%)");
Pattern pattern = Pattern.compile("([;,]?)(((-?\\d[,-]?\\d?['-]*)?[^%0-9>≥.<≤-]+)+)([0-9>≥.<≤-]+%)");
// Pattern pattern = Pattern.compile("-?\\d[,-]?\\d?['-]*");
Pattern pattern2 = Pattern.compile("(\\d+)%");
Matcher matcher = pattern.matcher(str);
Map<String, Integer> map = new HashMap<>();
while (matcher.find()) {
String group = matcher.group();
System.out.println("0===>>> " + group);
System.out.println("1===>>> " + matcher.group(1));
System.out.println("2===>>> " + matcher.group(2));
System.out.println("3===>>> " + matcher.group(3));
System.out.println("4===>>> " + matcher.group(4));
System.out.println("5===>>> " + matcher.group(5));
Matcher matcher2 = pattern2.matcher(group);
if (matcher2.find()) {
map.put(group, Integer.valueOf(matcher2.group(1)));
}
System.out.println("==============");
}
// System.out.println(map);
}
@Test
public void test055() {
String str = "乙酸乙酯30-50%2-乙基-2-(羟甲基)-1,3-丙二醇与1,3-二异氰酸根合甲基苯和2,2'-氧二乙醇的聚合物1-10%";
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
@Test
public void test06() {
String content = "3.3+2.3+8";
String regStr = "(\\d(\\.\\d)?\\+)*(\\d(\\.\\d)?)";
// String content = "1A2/Y2.2/100/22 CN/C230409 PI:007";
// String regStr = "[0-9A-Z]{2,3}/[A-Z]\\d\\.\\d/.+";
// String regStr = "([^/]+/)*[^/]+";
boolean b = Pattern.matches(regStr, content);
System.out.println("整体匹配= " + b);
}
@Test
public void test07() {
String str = "a,bc";
String[] split = str.split("[,]");
for (String s : split) {
System.out.println(s);
}
}
@Test
public void test08() {
Pattern p = Pattern.compile("产品.*含");
String str = "产品中主要含1-甲氧基-2-乙酰";
String s = p.matcher(str).replaceAll("");
System.out.println(s);
}
}

@ -0,0 +1,37 @@
package com.renchao;
import org.junit.Test;
import java.io.IOException;
import java.util.UUID;
public class StringFormatDemo {
public static void main(String[] args) {
String format = String.format("aaa%s,bbb%s,ccc%s", "111", 222, "333");
System.out.println(format);
String s = String.format("%s/%s/%s/%s.pdf", "c:", "a", "b", UUID.randomUUID());
System.out.println(s);
}
@Test
public void test01() {
StringFormatDemo demo = new StringFormatDemo();
String t = demo.t();
System.out.println(t);
}
public String t() {
try {
// int i =4 / 0;
return "try";
} catch (Exception e) {
return "catch";
} finally {
// return "finally";
System.out.println("ccc");
}
}
}

@ -0,0 +1,52 @@
package com.renchao;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipDemo {
public static void main(String[] args) throws Exception {
// 创建一个ZipOutputStream类的对象
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("C:\\Users\\RENCHAO\\Desktop\\新建文件夹\\output.zip"));
// 创建一个File对象表示要压缩的文件夹
File file = new File("C:\\Users\\RENCHAO\\Desktop\\aa");
// 调用compress方法将file对象压缩到out对象中
compress(out, file, "");
// 关闭out对象
out.close();
}
public static void compress(ZipOutputStream out, File file, String base) throws Exception {
if (file.isDirectory()) {
// 如果file对象是一个目录则获取该目录下的所有文件和目录
File[] files = file.listFiles();
// 如果files数组不为空则遍历files数组中的所有元素
if (files != null && files.length > 0) {
for (File f : files) {
// 递归调用compress方法将f对象压缩到out对象中
compress(out, f, base + file.getName() + "/");
}
}
} else {
// 如果file对象是一个文件则创建一个ZipEntry对象表示该文件在压缩包中的路径和名称
ZipEntry entry = new ZipEntry(base + file.getName());
// 将entry对象添加到out对象中
out.putNextEntry(entry);
// 创建一个FileInputStream类的对象
FileInputStream in = new FileInputStream(file);
// 创建一个byte数组
byte[] buffer = new byte[1024];
int len;
// 读取in对象中的数据到buffer数组中直到读取完毕
while ((len = in.read(buffer)) > 0) {
// 将buffer数组中的数据写入到out对象中
out.write(buffer, 0, len);
}
// 关闭in对象
in.close();
}
}
}

@ -0,0 +1,28 @@
package com.renchao;
import org.junit.Test;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ZonedDateTimeDemo {
@Test
public void test09() throws InterruptedException {
// long timestamp = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// System.out.println(timestamp);
//// Thread.sleep(5000);
// System.out.println(System.currentTimeMillis() - timestamp);
// System.out.println(30<<1<<2);
ZonedDateTime zonedDateTime = ZonedDateTime.of(2023, 4, 13, 12, 57, 0, 0, ZoneId.systemDefault());
long l = zonedDateTime.toInstant().toEpochMilli();
System.out.println(l);
System.out.println(System.currentTimeMillis());
System.out.println((System.currentTimeMillis() - 1681365120000L) /1000/60);
System.out.println(System.currentTimeMillis());
}
}

@ -0,0 +1,40 @@
<?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">
<parent>
<artifactId>agile-data</artifactId>
<groupId>com.jiuyv</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>agile-data-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,29 @@
package com.jiuyv.agile.data.api;
import com.jiuyv.agile.data.web.R;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
/**
* API
*
* @author yulei
*/
public interface AgileApi {
/**
*
* @param id
* @return
*/
@PostMapping(value = "/dataApis/{id}/release")
public R<Object> releaseDataApi(@PathVariable Long id);
/**
*
* @param id
* @return
*/
@PostMapping(value = "/dataApis/{id}/cancel")
public R<Object> cancelDataApi(@PathVariable Long id);
}

@ -0,0 +1,37 @@
package com.jiuyv.agile.data.dto.enums;
public enum AlgorithmCrypto {
BASE64("1", "BASE64加密"),
MD5("2", "MD5加密"),
SHA_1("3", "SHA_1加密"),
SHA_256("4", "SHA_256加密"),
AES("5", "AES加密"),
DES("6", "DES加密");
private final String key;
private final String val;
AlgorithmCrypto(String key, String val) {
this.key = key;
this.val = val;
}
public String getKey() {
return key;
}
public String getVal() {
return val;
}
public static AlgorithmCrypto getAlgorithmCrypto(String algorithmCrypt) {
for (AlgorithmCrypto type : AlgorithmCrypto.values()) {
if (type.key.equals(algorithmCrypt)) {
return type;
}
}
return BASE64;
}
}

@ -0,0 +1,33 @@
package com.jiuyv.agile.data.dto.enums;
public enum CipherType {
REGEX("1", "正则替换"),
ALGORITHM("2", "加密算法");
private final String key;
private final String val;
CipherType(String key, String val) {
this.key = key;
this.val = val;
}
public String getKey() {
return key;
}
public String getVal() {
return val;
}
public static CipherType getCipherType(String cipherType) {
for (CipherType type : CipherType.values()) {
if (type.key.equals(cipherType)) {
return type;
}
}
return REGEX;
}
}

@ -0,0 +1,83 @@
package com.jiuyv.agile.data.dto.enums;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
public enum ParamType {
String("1", "字符串"),
Integer("2", "整型"),
Float("3", "浮点型"),
Date("4", "时间"),
List("5", "集合");
private final String key;
private final String val;
ParamType(String key, String val) {
this.key = key;
this.val = val;
}
public String getKey() {
return key;
}
public String getVal() {
return val;
}
public static Object parse(ParamType paramType, Object obj) {
if (obj == null) {
return null;
}
switch (paramType) {
case String:
try {
return (java.lang.String)obj;
} catch (Exception e) {
throw new RuntimeException("参数值[" + obj + "]不是" + String.getVal() + "数据类型]");
}
case Float:
try {
return new BigDecimal(obj.toString()).doubleValue();
} catch (Exception e) {
throw new RuntimeException("参数值[" + obj + "]不是" + Float.getVal() + "数据类型]");
}
case Integer:
try {
return (java.lang.Integer)obj;
} catch (Exception e) {
throw new RuntimeException("参数值[" + obj + "]不是" + Integer.getVal() + "数据类型]");
}
case List:
try {
return (java.util.List<?>)obj;
} catch (Exception e) {
throw new RuntimeException("参数值[" + obj + "]不是" + List.getVal() + "数据类型]");
}
case Date:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(obj.toString());
} catch (Exception e) {
try {
return sdf.parse(obj.toString());
} catch (Exception ex) {
throw new RuntimeException("参数值[" + obj + "]不是" + Date.getVal() + "数据类型]");
}
}
}
return null;
}
public static ParamType getParamType(String paramType) {
for (ParamType type : ParamType.values()) {
if (type.key.equals(paramType)) {
return type;
}
}
return String;
}
}

@ -0,0 +1,39 @@
package com.jiuyv.agile.data.dto.enums;
public enum RegexCrypto {
CHINESE_NAME("1", "中文姓名"),
ID_CARD("2", "身份证号"),
FIXED_PHONE("3", "固定电话"),
MOBILE_PHONE("4", "手机号码"),
ADDRESS("5", "地址"),
EMAIL("6", "电子邮箱"),
BANK_CARD("7", "银行卡号"),
CNAPS_CODE("8", "公司开户银行联号");
private final String key;
private final String val;
RegexCrypto(String key, String val) {
this.key = key;
this.val = val;
}
public String getKey() {
return key;
}
public String getVal() {
return val;
}
public static RegexCrypto getRegexCrypto(String regexCrypt) {
for (RegexCrypto type : RegexCrypto.values()) {
if (type.key.equals(regexCrypt)) {
return type;
}
}
return CHINESE_NAME;
}
}

@ -0,0 +1,50 @@
package com.jiuyv.agile.data.dto.enums;
public enum WhereType {
EQUALS("1", "=", "等于"),
NOT_EQUALS("2", "!=", "不等于"),
LIKE("3", "LIKE", "全模糊查询"),
LIKE_LEFT("4", "LIKE", "左模糊查询"),
LIKE_RIGHT("5", "LIKE", "右模糊查询"),
GREATER_THAN("6", ">", "大于"),
GREATER_THAN_EQUALS("7", ">=", "大于等于"),
LESS_THAN("8", "<", "小于"),
LESS_THAN_EQUALS("9", "<=", "小于等于"),
NULL("10", "IS NULL", "是否为空"),
NOT_NULL("11", "IS NOT NULL", "是否不为空"),
IN("12", "IN", "IN");
private final String type;
private final String key;
private final String desc;
WhereType(String type, String key, String desc) {
this.type = type;
this.key = key;
this.desc = desc;
}
public String getType() {
return type;
}
public String getKey() {
return key;
}
public String getDesc() {
return desc;
}
public static WhereType getWhereType(String whereType) {
for (WhereType type : WhereType.values()) {
if (type.type.equals(whereType)) {
return type;
}
}
return EQUALS;
}
}

@ -0,0 +1,46 @@
package com.jiuyv.agile.data.dto.request;
import java.util.Objects;
/**
* <p>
* API
* </p>
*/
public class ApiMaskQuery extends BaseQueryParams {
private static final long serialVersionUID=1L;
private String maskName;
private Long apiId;
public String getMaskName() {
return maskName;
}
public void setMaskName(String maskName) {
this.maskName = maskName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApiMaskQuery that = (ApiMaskQuery) o;
return maskName.equals(that.maskName) && apiId.equals(that.apiId);
}
@Override
public int hashCode() {
return Objects.hash(maskName, apiId);
}
public Long getApiId() {
return apiId;
}
public void setApiId(Long apiId) {
this.apiId = apiId;
}
}

@ -0,0 +1,82 @@
package com.jiuyv.agile.data.dto.request;
import java.io.Serializable;
import java.util.List;
public class BaseQueryParams implements Serializable {
private static final long serialVersionUID = 1L;
// 关键字
private String keyword;
// 当前页码
private Integer pageNum = 1;
// 分页条数
private Integer pageSize = 20;
// 排序
private List<OrderItem> orderList;
// 数据权限
private String dataScope;
public class OrderItem{
private String column;
private boolean asc;
public String getColumn() {
return column;
}
public void setColumn(String column) {
this.column = column;
}
public boolean isAsc() {
return asc;
}
public void setAsc(boolean asc) {
this.asc = asc;
}
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public List<OrderItem> getOrderList() {
return orderList;
}
public void setOrderList(List<OrderItem> orderList) {
this.orderList = orderList;
}
public String getDataScope() {
return dataScope;
}
public void setDataScope(String dataScope) {
this.dataScope = dataScope;
}
}

@ -0,0 +1,96 @@
package com.jiuyv.agile.data.dto.request;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Model
*/
public class DbSchema implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@NotBlank(message = "主机不能为空")
private String host;
/**
*
*/
@NotNull(message = "端口不能为空")
private Integer port;
/**
*
*/
@NotBlank(message = "用户名不能为空")
private String username;
/**
*
*/
@NotBlank(message = "密码不能为空")
private String password;
/**
*
*/
private String dbName;
/**
*
*/
private String sid;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}

@ -0,0 +1,97 @@
package com.jiuyv.agile.data.dto.request;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* Model
*/
public class ExecuteConfig implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@NotBlank(message = "数据源不能为空")
private Long sourceId;
/**
*
*/
@NotNull(message = "配置方式不能为空")
private String configType;
/**
*
*/
private Long tableId;
/**
*
*/
private String tableName;
/**
*
*/
@Valid
private List<FieldParam> fieldParams;
/**
* SQL
*/
private String sqlText;
public Long getSourceId() {
return sourceId;
}
public void setSourceId(Long sourceId) {
this.sourceId = sourceId;
}
public String getConfigType() {
return configType;
}
public void setConfigType(String configType) {
this.configType = configType;
}
public Long getTableId() {
return tableId;
}
public void setTableId(Long tableId) {
this.tableId = tableId;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public List<FieldParam> getFieldParams() {
return fieldParams;
}
public void setFieldParams(List<FieldParam> fieldParams) {
this.fieldParams = fieldParams;
}
public String getSqlText() {
return sqlText;
}
public void setSqlText(String sqlText) {
this.sqlText = sqlText;
}
}

@ -0,0 +1,167 @@
package com.jiuyv.agile.data.dto.request;
import java.io.Serializable;
/**
* Model
*/
public class FieldParam implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
private String columnName;
/**
*
*/
private String dataType;
/**
*
*/
private Integer dataLength;
/**
*
*/
private Integer dataPrecision;
/**
*
*/
private Integer dataScale;
/**
*
*/
private String columnKey;
/**
*
*/
private String columnNullable;
/**
*
*/
private Integer columnPosition;
/**
*
*/
private String dataDefault;
/**
*
*/
private String columnComment;
/**
*
*/
private String reqable;
/**
*
*/
private String resable;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public Integer getDataLength() {
return dataLength;
}
public void setDataLength(Integer dataLength) {
this.dataLength = dataLength;
}
public Integer getDataPrecision() {
return dataPrecision;
}
public void setDataPrecision(Integer dataPrecision) {
this.dataPrecision = dataPrecision;
}
public Integer getDataScale() {
return dataScale;
}
public void setDataScale(Integer dataScale) {
this.dataScale = dataScale;
}
public String getColumnKey() {
return columnKey;
}
public void setColumnKey(String columnKey) {
this.columnKey = columnKey;
}
public String getColumnNullable() {
return columnNullable;
}
public void setColumnNullable(String columnNullable) {
this.columnNullable = columnNullable;
}
public Integer getColumnPosition() {
return columnPosition;
}
public void setColumnPosition(Integer columnPosition) {
this.columnPosition = columnPosition;
}
public String getDataDefault() {
return dataDefault;
}
public void setDataDefault(String dataDefault) {
this.dataDefault = dataDefault;
}
public String getColumnComment() {
return columnComment;
}
public void setColumnComment(String columnComment) {
this.columnComment = columnComment;
}
public String getReqable() {
return reqable;
}
public void setReqable(String reqable) {
this.reqable = reqable;
}
public String getResable() {
return resable;
}
public void setResable(String resable) {
this.resable = resable;
}
}

@ -0,0 +1,53 @@
package com.jiuyv.agile.data.dto.request;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Model
*/
public class FieldRule implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@NotBlank(message = "字段名称不能为空")
private String fieldName;
/**
*
*/
@NotNull(message = "脱敏类型不能为空")
private String cipherType;
/**
*
*/
@NotNull(message = "规则类型不能为空")
private String cryptType;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getCipherType() {
return cipherType;
}
public void setCipherType(String cipherType) {
this.cipherType = cipherType;
}
public String getCryptType() {
return cryptType;
}
public void setCryptType(String cryptType) {
this.cryptType = cryptType;
}
}

@ -0,0 +1,52 @@
package com.jiuyv.agile.data.dto.request;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Model
*/
public class RateLimit implements Serializable {
private static final long serialVersionUID=1L;
/**
* 0:1
*/
@NotNull(message = "是否限流不能为空")
private String enable;
/**
* 5
*/
private Integer times = 5;
/**
* 60
*/
private Integer seconds = 60;
public String getEnable() {
return enable;
}
public void setEnable(String enable) {
this.enable = enable;
}
public Integer getTimes() {
return times;
}
public void setTimes(Integer times) {
this.times = times;
}
public Integer getSeconds() {
return seconds;
}
public void setSeconds(Integer seconds) {
this.seconds = seconds;
}
}

@ -0,0 +1,111 @@
package com.jiuyv.agile.data.dto.request;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Model
*/
public class ReqParam implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@NotBlank(message = "参数名称不能为空")
private String paramName;
/**
*
*/
@NotNull(message = "是否为空不能为空")
private String nullable;
/**
*
*/
@NotBlank(message = "描述不能为空")
private String paramComment;
/**
*
*/
@NotNull(message = "操作符不能为空")
private String whereType;
/**
*
*/
@NotNull(message = "参数类型不能为空")
private String paramType;
/**
*
*/
@NotBlank(message = "示例值不能为空")
private String exampleValue;
/**
*
*/
@NotBlank(message = "默认值不能为空")
private String defaultValue;
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getNullable() {
return nullable;
}
public void setNullable(String nullable) {
this.nullable = nullable;
}
public String getParamComment() {
return paramComment;
}
public void setParamComment(String paramComment) {
this.paramComment = paramComment;
}
public String getWhereType() {
return whereType;
}
public void setWhereType(String whereType) {
this.whereType = whereType;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getExampleValue() {
return exampleValue;
}
public void setExampleValue(String exampleValue) {
this.exampleValue = exampleValue;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
}

@ -0,0 +1,34 @@
package com.jiuyv.agile.data.dto.request;
import java.io.Serializable;
/**
* API
*
* @author yulei
*/
public class ReqVo implements Serializable {
/** 报文内容 */
private String body;
/** 签名 */
private String sign;
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}

@ -0,0 +1,82 @@
package com.jiuyv.agile.data.dto.response;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Model
*/
public class ResParam implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@NotBlank(message = "字段名称不能为空")
private String fieldName;
/**
*
*/
@NotBlank(message = "描述不能为空")
private String fieldComment;
/**
*
*/
@NotNull(message = "数据类型不能为空")
private String dataType;
/**
*
*/
@NotBlank(message = "示例值不能为空")
private String exampleValue;
/**
*
*/
private String fieldAliasName;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldComment() {
return fieldComment;
}
public void setFieldComment(String fieldComment) {
this.fieldComment = fieldComment;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getExampleValue() {
return exampleValue;
}
public void setExampleValue(String exampleValue) {
this.exampleValue = exampleValue;
}
public String getFieldAliasName() {
return fieldAliasName;
}
public void setFieldAliasName(String fieldAliasName) {
this.fieldAliasName = fieldAliasName;
}
}

@ -0,0 +1,55 @@
package com.jiuyv.agile.data.dto.response;
import com.jiuyv.agile.data.web.ResultCode;
import java.io.Serializable;
/**
* API
*
* @author yulei
*/
public class RespVo implements Serializable {
/** 返回码*/
private Integer respCode;
/** 返回说明 */
private String respDesc;
public RespVo() {
}
public RespVo(Integer code, String message) {
this.respCode = code;
this.respDesc = message;
}
public static RespVo ok(){
return new RespVo(ResultCode.SUCCESS.getCode(),ResultCode.SUCCESS.getMessage());
}
public Integer getRespCode() {
return respCode;
}
public void setRespCode(Integer respCode) {
this.respCode = respCode;
}
public String getRespDesc() {
return respDesc;
}
public void setRespDesc(String respDesc) {
this.respDesc = respDesc;
}
@Override
public String toString() {
return "RespVo{" +
"respCode='" + respCode + '\'' +
", respDesc='" + respDesc + '\'' +
'}';
}
}

@ -0,0 +1,20 @@
package com.jiuyv.agile.data.web;
/**
* @ClassName : IErrorCode
* @Description : API
* @Author : sky
* @Date: 2023-06-06 16:33
*/
public interface IErrorCode {
/**
*
*/
Integer getCode();
/**
*
*/
String getMessage();
}

@ -0,0 +1,107 @@
package com.jiuyv.agile.data.web;
import com.jiuyv.agile.data.web.constant.HttpStatus;
import java.io.Serializable;
/**
*
*
* @author admin
*/
public class R<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = HttpStatus.SUCCESS;
/** 失败 */
public static final int FAIL = HttpStatus.ERROR;
private int code;
private String msg;
private T data;
public static <T> R<T> ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail()
{
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg)
{
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
}

@ -0,0 +1,70 @@
package com.jiuyv.agile.data.web;
/**
* API
* Created by macro on 2019/4/19.
*/
public enum ResultCode implements IErrorCode {
/** success : 成功. */
SUCCESS(200, "操作成功"),
ACCEPTED(202, "请求已经被接受"),
NO_CONTENT(204, "操作已经执行成功,但是没有返回数据"),
MOVED_PERM(301, "资源已被移除"),
SEE_OTHER(303, "重定向"),
NOT_MODIFIED(304, "资源没有被修改"),
BAD_REQUEST(400, "参数列表错误(缺少,格式不匹配)"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "访问受限,授权过期"),
NOT_FOUND(404, "资源,服务未找到"),
BAD_METHOD(405, "不允许的http方法"),
CONFLICT(409, "资源冲突,或者资源被锁"),
ERROR(500, "系统内部错误"),
NOT_IMPLEMENTED(501, "接口未实现"),
//PROCESS("process", "订单处理中,请稍后查询"),
//FAILED("failed", "操作失败"),
//VALIDATE_FAILED("input_not_valid", "输入不合法"),
//REPEAT_SUBMIT("duplicate_req_id", "请勿重复提交"),
//AUTHORIZATION_LIMIT("authorization limit", "权限限制"),
//UNAUTHORIZED("401", "暂未登录或token已经过期"),
//
//ILLEGALLY("illegally request", "不合法请求"),
///** input_not_valid : 输入不合法. */
//INPUT_NOT_VALID("input_not_valid", "输入不合法"),
///** duplicate_req_id : 重复请求. */
//DUPLICATE_REQ_ID("duplicate_req_id","重复请求"),
///** duplicate_order : 订单重复. */
//DUPLICATE_ORDER("duplicate_order","订单重复"),
//
///** product_limit : 商品限购 */
//SYS_ERROR("sys_error","系统异常"),
///** business_error : 调用返回非成功 */
//BUSINESS_ERROR("business_error","调用返回非成功"),
///** sql_lock_exception : 乐观锁异常*/
//SQL_EXCEPTION("sql_lock_exception","乐观锁异常"),
//
///** file_not_exist,请输入正确的权益号 */
//FILE_NOT_EXIST("file_not_exist","文件不存在"),
///** file_no_data,文件内容为空 */
//FILE_NO_DATA("file_no_data","文件内容为空");
;
private Integer code;
private String message;
private ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}

@ -0,0 +1,89 @@
package com.jiuyv.agile.data.web.constant;
/**
*
*
* @author admin
*/
public class HttpStatus
{
/**
*
*/
public static final int SUCCESS = 200;
/**
*
*/
public static final int CREATED = 201;
/**
*
*/
public static final int ACCEPTED = 202;
/**
*
*/
public static final int NO_CONTENT = 204;
/**
*
*/
public static final int MOVED_PERM = 301;
/**
*
*/
public static final int SEE_OTHER = 303;
/**
*
*/
public static final int NOT_MODIFIED = 304;
/**
*
*/
public static final int BAD_REQUEST = 400;
/**
*
*/
public static final int UNAUTHORIZED = 401;
/**
* 访
*/
public static final int FORBIDDEN = 403;
/**
*
*/
public static final int NOT_FOUND = 404;
/**
* http
*/
public static final int BAD_METHOD = 405;
/**
*
*/
public static final int CONFLICT = 409;
/**
*
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
*
*/
public static final int ERROR = 500;
/**
*
*/
public static final int NOT_IMPLEMENTED = 501;
}

@ -0,0 +1,76 @@
<?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">
<parent>
<artifactId>agile-data</artifactId>
<groupId>com.jiuyv</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>agile-data-service</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.jiuyv</groupId>
<artifactId>agile-data-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- postgresql连接 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,30 @@
package com.jiuyv.agile.data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author yulei
*/
@SpringBootApplication
@EnableScheduling
public class AgileDataApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(AgileDataApplication.class);
public static void main(String[] args) {
SpringApplication.run(AgileDataApplication.class, args);
LOGGER.info("(♥◠‿◠)ノ゙ 模块启动成功゙ \n"+
" ___ ___ ___ \n"+
" |\\ \\ |\\ \\ / /| \n"+
" \\ \\ \\ \\ \\ \\/ / / \n"+
" __ \\ \\ \\ \\ \\ / / \n"+
" |\\ \\\\_\\ \\ \\/ / / \n"+
" \\ \\________\\ __/ / / \n"+
" \\|________| |\\___/ / \n"+
" \\|___|/ \n"
);
}
}

@ -0,0 +1,211 @@
package com.jiuyv.agile.data.common.constants;
public class DataConstant {
/**
* Oauth2
*/
public enum Security {
//请求头TOKEN名称
TOKENHEADER("gatewayToken"),
//请求头TOKEN值
TOKENVALUE("datax:gateway:123456"),
//OAUTH2请求头
AUTHORIZATION("Authorization"),
//OAUTH2令牌类型
TOKENTYPE("bearer "),
//security授权角色前缀
ROLEPREFIX("ROLE_");
Security(String val){
this.val = val;
}
private final String val;
public String getVal() {
return val;
}
}
/**
*
*/
public enum TrueOrFalse {
FALSE("0",false),
TRUE("1",true);
TrueOrFalse(String key, boolean val){
this.key = key;
this.val = val;
}
private final String key;
private final boolean val;
public String getKey() {
return key;
}
public boolean getVal() {
return val;
}
}
/**
*
*/
public enum UserAdditionalInfo {
LICENSE("license", "datax"),
USER("user", "用户"),
USERID("user_id", "用户ID"),
USERNAME("username", "用户名"),
NICKNAME("nickname", "用户昵称"),
DEPT("user_dept", "用户部门"),
ROLE("user_role", "用户角色"),
POST("user_post", "用户岗位");
UserAdditionalInfo(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
*
*/
public enum EnableState {
DISABLE("0","禁用"),
ENABLE("1","启用");
EnableState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
*
*/
public enum AuditState{
WAIT("1","待提交"),
BACK("2", "已退回"),
AUDIT("3","审核中"),
AGREE("4","通过"),
REJECT("5","不通过"),
CANCEL("6", "已撤销");
AuditState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
*
*/
public enum MenuType{
MODULE("0","模块"),
MENU("1","菜单"),
BUTTON("2","按钮");
MenuType(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
*
*/
public enum DataScope{
ALL("1","全部数据权限"),
CUSTOM("2","自定义数据权限"),
DEPT("3","本部门数据权限"),
DEPTANDCHILD("4","本部门及以下数据权限"),
SELF("5","仅本人数据权限");
DataScope(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* Api
*/
public enum ApiState{
WAIT("1","待发布"),
RELEASE("2","已发布"),
CANCEL("3","已下线");
ApiState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
}

@ -0,0 +1,33 @@
package com.jiuyv.agile.data.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jiuyv.agile.data.handler.MappingHandlerMapping;
import com.jiuyv.agile.data.handler.RequestHandler;
import com.jiuyv.agile.data.handler.RequestInterceptor;
import com.jiuyv.agile.data.service.impl.ApiMappingEngine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
public class ApiMappingConfig {
@Bean
public MappingHandlerMapping mappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping,
ApiMappingEngine apiMappingEngine,
ObjectMapper objectMapper) {
MappingHandlerMapping mappingHandlerMapping = new MappingHandlerMapping();
mappingHandlerMapping.setHandler(requestHandler(apiMappingEngine, objectMapper));
mappingHandlerMapping.setRequestMappingHandlerMapping(requestMappingHandlerMapping);
return mappingHandlerMapping;
}
@Bean
public RequestHandler requestHandler(ApiMappingEngine apiMappingEngine, ObjectMapper objectMapper) {
RequestHandler handler = new RequestHandler();
handler.setApiMappingEngine(apiMappingEngine);
handler.setObjectMapper(objectMapper);
handler.setRequestInterceptor(new RequestInterceptor());
return handler;
}
}

@ -0,0 +1,43 @@
package com.jiuyv.agile.data.controller;
import com.jiuyv.agile.data.service.AgileApiService;
import com.jiuyv.agile.data.web.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* API
*
* @author yulei
*/
@RestController
public class AgileApiController {
@Autowired
private AgileApiService agileApiService;
/**
*
* @param id
* @return
*/
@PostMapping(value = "/dataApis/{id}/release")
public R<Object> releaseDataApi(@PathVariable Long id){
agileApiService.releaseDataApi(id);
return R.ok();
}
/**
*
* @param id
* @return
*/
@PostMapping(value = "/dataApis/{id}/cancel")
public R<Object> cancelDataApi(@PathVariable Long id){
agileApiService.cancelDataApi(id);
return R.ok();
}
}

@ -0,0 +1,7 @@
package com.jiuyv.agile.data.controller;
import com.jiuyv.agile.data.api.AgileApi;
public interface ts extends AgileApi {
}

@ -0,0 +1,31 @@
package com.jiuyv.agile.data.controller;
import com.jiuyv.agile.data.api.AgileApi;
import com.jiuyv.agile.data.service.AgileApiService;
import com.jiuyv.agile.data.web.R;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class tt implements AgileApi {
/**
*
*
* @param id
* @return
*/
@Override
public R<Object> releaseDataApi(Long id) {
return null;
}
/**
*
*
* @param id
* @return
*/
@Override
public R<Object> cancelDataApi(Long id) {
return null;
}
}

@ -0,0 +1,12 @@
package com.jiuyv.agile.data.database;
public interface DataSourceFactory {
/**
*
*
* @param property
* @return
*/
DbQuery createDbQuery(DbQueryProperty property);
}

@ -0,0 +1,134 @@
package com.jiuyv.agile.data.database;
public class DbColumn {
/**
*
*/
private String colName;
/**
*
*/
private String dataType;
/**
*
*/
private String dataLength;
/**
*
*/
private String dataPrecision;
/**
*
*/
private String dataScale;
/**
*
*/
private Boolean colKey;
/**
*
*/
private Boolean nullable;
/**
*
*/
private Integer colPosition;
/**
*
*/
private String dataDefault;
/**
*
*/
private String colComment;
public String getColName() {
return colName;
}
public void setColName(String colName) {
this.colName = colName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getDataLength() {
return dataLength;
}
public void setDataLength(String dataLength) {
this.dataLength = dataLength;
}
public String getDataPrecision() {
return dataPrecision;
}
public void setDataPrecision(String dataPrecision) {
this.dataPrecision = dataPrecision;
}
public String getDataScale() {
return dataScale;
}
public void setDataScale(String dataScale) {
this.dataScale = dataScale;
}
public Boolean getColKey() {
return colKey;
}
public void setColKey(Boolean colKey) {
this.colKey = colKey;
}
public Boolean getNullable() {
return nullable;
}
public void setNullable(Boolean nullable) {
this.nullable = nullable;
}
public Integer getColPosition() {
return colPosition;
}
public void setColPosition(Integer colPosition) {
this.colPosition = colPosition;
}
public String getDataDefault() {
return dataDefault;
}
public void setDataDefault(String dataDefault) {
this.dataDefault = dataDefault;
}
public String getColComment() {
return colComment;
}
public void setColComment(String colComment) {
this.colComment = colComment;
}
}

@ -0,0 +1,48 @@
package com.jiuyv.agile.data.database;
import org.springframework.jdbc.core.RowMapper;
/**
*
*/
public interface DbDialect {
RowMapper<DbTable> tableMapper();
RowMapper<DbColumn> columnMapper();
/**
*
*
* @param dbName
* @param tableName
* @return
*/
String columns(String dbName, String tableName);
/**
*
*
* @param dbName
* @return
*/
String tables(String dbName);
/**
* sql
*
* @param sql
* @param offset
* @param count
* @return
*/
String buildPaginationSql(String sql, long offset, long count);
/**
* count sql
*
* @param sql
* @return
*/
String count(String sql);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save