Initial commit
This commit is contained in:
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/vcs.xml
|
||||
.idea/misc.xml
|
||||
.idea/encodings.xml
|
||||
.idea/CoolRequestCommonStatePersistent.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
|
||||
### cache file ###
|
||||
/apolloConfig/
|
||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
15
.idea/checkstyle-idea.xml
generated
Normal file
15
.idea/checkstyle-idea.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
||||
<checkstyleVersion>10.26.1</checkstyleVersion>
|
||||
<scanScope>JavaOnly</scanScope>
|
||||
<option name="thirdPartyClasspath" />
|
||||
<option name="activeLocationIds" />
|
||||
<option name="locations">
|
||||
<list>
|
||||
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
|
||||
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
106
demo/lingniu-framework-demo/pom.xml
Normal file
106
demo/lingniu-framework-demo/pom.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>lingniu-framework-demo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-apollo</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-redisson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-jetcache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-xxljob</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-mybatis</artifactId>
|
||||
</dependency>
|
||||
<!-- todo mybatis-demo使用h2数据库-->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.1.214</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-rocketmq</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-easyexcel</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-prometheus</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-nacos</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.lingniu.demo;
|
||||
|
||||
import com.alicp.jetcache.anno.config.EnableMethodCache;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@ComponentScan(basePackages = {"cn.lingniu.*"})
|
||||
//jetcache 注解
|
||||
@EnableMethodCache(basePackages = "cn.lingniu")
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.lingniu.demo.apollo;
|
||||
|
||||
import com.ctrip.framework.apollo.model.ConfigChange;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ApolloConfigChangeDemoListener {
|
||||
|
||||
|
||||
@ApolloConfigChangeListener()
|
||||
public void onChange(ConfigChangeEvent changeEvent) {
|
||||
for (String changedKey : changeEvent.changedKeys()) {
|
||||
ConfigChange changeInfo = changeEvent.getChange(changedKey);
|
||||
if(StringUtils.isEmpty(changeInfo)){continue;}
|
||||
log.info("apollo 配置变更 \r\n\t命名空间:{} \r\n\t属性:{} \r\n\t原值:{}\r\n\t新值:{}\r\n\t变更类型:{}"
|
||||
,changeInfo.getNamespace()
|
||||
,changeInfo.getPropertyName()
|
||||
,changeInfo.getOldValue()
|
||||
,changeInfo.getNewValue()
|
||||
,changeInfo.getChangeType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.demo.apollo;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping(value = "/demo/apollo")
|
||||
public class ApolloController {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ObjectDemoConfig objectDemoConfig;
|
||||
|
||||
@GetMapping("/apolloDemoConfig")
|
||||
public ObjectDemoConfig apolloDemoConfig() {
|
||||
System.out.println("apolloDemoConfig:" + JSONObject.toJSONString(objectDemoConfig));
|
||||
return objectDemoConfig;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.lingniu.demo.apollo;
|
||||
|
||||
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableApolloConfig
|
||||
public class ObjcetDemoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ObjectDemoConfig apolloDemoConfig() {
|
||||
return new ObjectDemoConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.lingniu.demo.apollo;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "apollo.demo")
|
||||
public class ObjectDemoConfig implements Serializable {
|
||||
|
||||
private String stringDemo = "";
|
||||
|
||||
private Boolean booleanDemo = true;
|
||||
|
||||
private List<String> listDemo = Lists.newArrayList();
|
||||
|
||||
private Set<String> setDemo = Sets.newHashSet();
|
||||
|
||||
private Map<String, String> hashDemo = Maps.newHashMap();
|
||||
|
||||
private Map<String, ObjectDemo> hashObjectDemo = Maps.newHashMap();
|
||||
|
||||
private ObjectDemo objectDemo = new ObjectDemo();
|
||||
|
||||
|
||||
@Data
|
||||
public static class ObjectDemo {
|
||||
private String testObjcet;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.lingniu.demo.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/demo/db")
|
||||
@Slf4j
|
||||
public class JobZookeeperController {
|
||||
|
||||
@Autowired
|
||||
JobZookeeperServerMapper jobZookeeperServerMapper;
|
||||
|
||||
@GetMapping("/page")
|
||||
public Page<JobZookeeperServer> getJobZookeeperServerPage() {
|
||||
Page<JobZookeeperServer> jobZookeeperServerPage = jobZookeeperServerMapper.selectPage(Page.of(1, 1),
|
||||
new LambdaQueryWrapper<JobZookeeperServer>().select(JobZookeeperServer::getName, JobZookeeperServer::getAddress, JobZookeeperServer::getDigest,
|
||||
JobZookeeperServer::getJmxEnable, JobZookeeperServer::getJmxPort, JobZookeeperServer::getMessage, JobZookeeperServer::getCreateTime,
|
||||
JobZookeeperServer::getUpdateTime, JobZookeeperServer::getStatus, JobZookeeperServer::getContactPhone, JobZookeeperServer::getUserName));
|
||||
log.info("jobZookeeperServerPage:{}", jobZookeeperServerPage);
|
||||
return jobZookeeperServerPage;
|
||||
}
|
||||
|
||||
@GetMapping("/add")
|
||||
public JobZookeeperServer addJobZookeeperServer() {
|
||||
JobZookeeperServer server = new JobZookeeperServer();
|
||||
server.setName("test");
|
||||
server.setAddress("127.0.0.1:2181");
|
||||
server.setDigest("");
|
||||
server.setJmxEnable(1);
|
||||
server.setJmxPort("");
|
||||
server.setMessage("");
|
||||
server.setCreateTime(new Date());
|
||||
server.setUpdateTime(new Date());
|
||||
server.setStatus(1);
|
||||
server.setContactPhone("");
|
||||
server.setUserName("");
|
||||
jobZookeeperServerMapper.insert(server);
|
||||
log.info("Added new JobZookeeperServer: {}", server);
|
||||
return server;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package cn.lingniu.demo.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* h2 建表语句:
|
||||
|
||||
CREATE TABLE job_zk_namespace (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
address VARCHAR(255),
|
||||
digest VARCHAR(255),
|
||||
jmx_enable INTEGER DEFAULT 1,
|
||||
jmx_port VARCHAR(255),
|
||||
message VARCHAR(255),
|
||||
create_time TIMESTAMP,
|
||||
update_time TIMESTAMP,
|
||||
status INTEGER DEFAULT 1,
|
||||
contact_phone VARCHAR(255),
|
||||
user_name VARCHAR(255)
|
||||
);
|
||||
|
||||
*/
|
||||
@Data
|
||||
@TableName("job_zk_namespace")
|
||||
public class JobZookeeperServer implements Serializable {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String address;
|
||||
|
||||
private String digest;
|
||||
|
||||
private Integer jmxEnable = 1;
|
||||
|
||||
private String jmxPort;
|
||||
|
||||
private String message;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
private Integer status = 1;
|
||||
|
||||
private String contactPhone;
|
||||
|
||||
private String userName;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lingniu.demo.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface JobZookeeperServerMapper extends BaseMapper<JobZookeeperServer> {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.demo.file;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class DemoData {
|
||||
@ExcelProperty("字符串标题")
|
||||
private String string;
|
||||
@ExcelProperty("日期标题")
|
||||
private Date date;
|
||||
@ExcelProperty("数字标题")
|
||||
private Double doubleData;
|
||||
/**
|
||||
* 忽略这个字段
|
||||
*/
|
||||
@ExcelIgnore
|
||||
private String ignore;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.lingniu.demo.file;
|
||||
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.util.ListUtils;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* todo https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write
|
||||
* easyexcel 性能好,api简单,上手更简单
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/demo/file")
|
||||
public class FileController {
|
||||
|
||||
@GetMapping("/test1")
|
||||
public String test1() {
|
||||
simpleWrite();
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 最简单的写
|
||||
* <p>
|
||||
* 1. 创建excel对应的实体对象 参照{@link DemoData}
|
||||
* <p>
|
||||
* 2. 直接写即可
|
||||
*/
|
||||
public void simpleWrite() {
|
||||
// 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入
|
||||
|
||||
// 写法1 JDK8+
|
||||
// since: 3.0.0-beta1
|
||||
String fileName = FileTestUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
|
||||
// 如果这里想使用03 则 传入excelType参数即可
|
||||
EasyExcel.write(fileName, DemoData.class)
|
||||
.sheet("模板")
|
||||
.doWrite(() -> {
|
||||
// 分页查询数据
|
||||
return data();
|
||||
});
|
||||
|
||||
// 写法2
|
||||
fileName = FileTestUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
|
||||
// 如果这里想使用03 则 传入excelType参数即可
|
||||
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
|
||||
|
||||
// 写法3
|
||||
fileName = FileTestUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写
|
||||
try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
|
||||
excelWriter.write(data(), writeSheet);
|
||||
}
|
||||
}
|
||||
|
||||
private List<DemoData> data() {
|
||||
List<DemoData> list = ListUtils.newArrayList();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
DemoData data = new DemoData();
|
||||
data.setString("字符串" + i);
|
||||
data.setDate(new Date());
|
||||
data.setDoubleData(0.56);
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package cn.lingniu.demo.file;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FileTestUtil {
|
||||
|
||||
public static InputStream getResourcesFileInputStream(String fileName) {
|
||||
return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);
|
||||
}
|
||||
|
||||
public static String getPath() {
|
||||
return FileTestUtil.class.getResource("/").getPath();
|
||||
}
|
||||
|
||||
public static TestPathBuild pathBuild() {
|
||||
return new TestPathBuild();
|
||||
}
|
||||
|
||||
public static File createNewFile(String pathName) {
|
||||
File file = new File(getPath() + pathName);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
} else {
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public static File readFile(String pathName) {
|
||||
return new File(getPath() + pathName);
|
||||
}
|
||||
|
||||
public static File readUserHomeFile(String pathName) {
|
||||
return new File(System.getProperty("user.home") + File.separator + pathName);
|
||||
}
|
||||
|
||||
/**
|
||||
* build to test file path
|
||||
**/
|
||||
public static class TestPathBuild {
|
||||
private TestPathBuild() {
|
||||
subPath = new ArrayList<>();
|
||||
}
|
||||
|
||||
private final List<String> subPath;
|
||||
|
||||
public TestPathBuild sub(String dirOrFile) {
|
||||
subPath.add(dirOrFile);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
if (CollectionUtils.isEmpty(subPath)) {
|
||||
return FileTestUtil.class.getResource("/").getPath();
|
||||
}
|
||||
if (subPath.size() == 1) {
|
||||
return FileTestUtil.class.getResource("/").getPath() + subPath.get(0);
|
||||
}
|
||||
StringBuilder path = new StringBuilder(FileTestUtil.class.getResource("/").getPath());
|
||||
path.append(subPath.get(0));
|
||||
for (int i = 1; i < subPath.size(); i++) {
|
||||
path.append(File.separator).append(subPath.get(i));
|
||||
}
|
||||
return path.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.lingniu.demo.jetcache.annotationDemo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class User implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Long id, String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package cn.lingniu.demo.jetcache.annotationDemo;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@Repository
|
||||
public class UserDao {
|
||||
|
||||
// 模拟数据库存储
|
||||
private final ConcurrentHashMap<Long, User> userDatabase = new ConcurrentHashMap<>();
|
||||
private final AtomicLong idGenerator = new AtomicLong(1);
|
||||
|
||||
/**
|
||||
* 根据ID获取用户信息,使用缓存
|
||||
* @param id 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
public User getUserById(Long id) {
|
||||
return userDatabase.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新用户
|
||||
* @param user 用户信息
|
||||
* @return 创建后的用户信息
|
||||
*/
|
||||
public User createUser(User user) {
|
||||
Long id = idGenerator.getAndIncrement();
|
||||
user.setId(id);
|
||||
userDatabase.put(id, user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息并更新缓存
|
||||
* @param user 更新后的用户信息
|
||||
* @return 更新后的用户信息
|
||||
*/
|
||||
public User updateUser(User user) {
|
||||
userDatabase.put(user.getId(), user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户并清除缓存
|
||||
* @param id 用户ID
|
||||
*/
|
||||
public void deleteUser(Long id) {
|
||||
userDatabase.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package cn.lingniu.demo.jetcache.annotationDemo;
|
||||
|
||||
import com.alicp.jetcache.anno.CacheInvalidate;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
import com.alicp.jetcache.anno.CacheUpdate;
|
||||
import com.alicp.jetcache.anno.Cached;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
/**
|
||||
* 根据ID获取用户信息,使用缓存
|
||||
* @param id 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
@Cached(area = "ca2", name = "user:", key = "#id", expire = 3600, localExpire = 600, cacheType = CacheType.BOTH)
|
||||
public User getUserById(Long id) {
|
||||
// 模拟数据库查询延迟
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return userDao.getUserById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息并更新缓存
|
||||
* @param user 更新后的用户信息
|
||||
* @return 更新后的用户信息
|
||||
*/
|
||||
@CacheUpdate(area = "ca2", name = "user:", key = "#user.id", value = "#user")
|
||||
public User updateUser(User user) {
|
||||
userDao.updateUser(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户并清除缓存
|
||||
* @param id 用户ID
|
||||
*/
|
||||
@CacheInvalidate(area = "ca2", name = "user:", key = "#id")
|
||||
public void deleteUser(Long id) {
|
||||
userDao.deleteUser(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public User createUser(User user) {
|
||||
return userDao.createUser(user);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cn.lingniu.demo.jetcache.controller;
|
||||
|
||||
import cn.lingniu.demo.jetcache.annotationDemo.User;
|
||||
import cn.lingniu.demo.jetcache.annotationDemo.UserService;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.alicp.jetcache.SimpleCacheManager;
|
||||
import com.alicp.jetcache.anno.CachePenetrationProtect;
|
||||
import com.alicp.jetcache.anno.CacheRefresh;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
import com.alicp.jetcache.anno.Cached;
|
||||
import com.alicp.jetcache.template.QuickConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/demo/cache")
|
||||
public class JetCacheController {
|
||||
|
||||
@Resource
|
||||
private SimpleCacheManager jcCacheManager;
|
||||
@Resource
|
||||
private UserService userService; //todo 可以直接使用
|
||||
|
||||
@GetMapping
|
||||
public String cache(
|
||||
@RequestParam String localArea,
|
||||
@RequestParam String remoteArea) {
|
||||
Cache<Object, Object> localCache = jcCacheManager.getOrCreateCache(QuickConfig.newBuilder(localArea, "user:").cacheType(CacheType.LOCAL).build());
|
||||
localCache.PUT("key1", "value3");
|
||||
Object value = localCache.GET("key1").getValue();
|
||||
log.info("value: {}", value);
|
||||
|
||||
Cache<Object, Object> remoteCache = jcCacheManager.getOrCreateCache(QuickConfig.newBuilder(remoteArea, "user:").build());
|
||||
remoteCache.PUT("key1", "value4");
|
||||
Object value1 = remoteCache.GET("key1").getValue();
|
||||
log.info("value1: {}", value1);
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
@GetMapping("/anno")
|
||||
@CachePenetrationProtect
|
||||
@Cached(name = "orderCache:", key = "#orderId", expire = 10, cacheType = CacheType.BOTH)
|
||||
@CacheRefresh(refresh = 10, timeUnit = TimeUnit.MINUTES)
|
||||
public KeyValueEntity getOrderById(String orderId) {
|
||||
KeyValueEntity keyValueEntity = new KeyValueEntity();
|
||||
keyValueEntity.setId(orderId);
|
||||
keyValueEntity.setKey("key");
|
||||
keyValueEntity.setValue("value");
|
||||
return keyValueEntity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/userTest")
|
||||
public String userTest() {
|
||||
userService.createUser(new User(1L, "create", "create" ));
|
||||
User temp1 = userService.getUserById(1L);
|
||||
userService.updateUser(new User(1L, "update", "update"));
|
||||
User temp2 = userService.getUserById(1L);
|
||||
userService.deleteUser(1L);
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.lingniu.demo.jetcache.controller;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
public class KeyValueEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
String id;
|
||||
String key;
|
||||
String value;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package cn.lingniu.demo.job;
|
||||
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* XxlJob开发示例(Bean模式)
|
||||
* <p>
|
||||
* 开发步骤:
|
||||
* 1、任务开发:在Spring Bean实例中,开发Job方法;
|
||||
* 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
|
||||
* 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
|
||||
* 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SampleXxlJob {
|
||||
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
|
||||
|
||||
|
||||
/**
|
||||
* 1、简单任务示例(Bean模式)
|
||||
*/
|
||||
@XxlJob("demoJobHandler")
|
||||
public void demoJobHandler() throws Exception {
|
||||
XxlJobHelper.log("XXL-JOB, Hello World.");
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
XxlJobHelper.log("beat at:" + i);
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
}
|
||||
// default success
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 2、分片广播任务
|
||||
*/
|
||||
@XxlJob("shardingJobHandler")
|
||||
public void shardingJobHandler() throws Exception {
|
||||
|
||||
// 分片参数
|
||||
int shardIndex = XxlJobHelper.getShardIndex();
|
||||
int shardTotal = XxlJobHelper.getShardTotal();
|
||||
|
||||
XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
|
||||
|
||||
// 业务逻辑
|
||||
for (int i = 0; i < shardTotal; i++) {
|
||||
if (i == shardIndex) {
|
||||
XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
|
||||
} else {
|
||||
XxlJobHelper.log("第 {} 片, 忽略", i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.lingniu.demo.microservice;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.base.CommonResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/demo/cloud")
|
||||
public class CloudController {
|
||||
|
||||
@Autowired
|
||||
private DemoFeignClient demoFeignClient;
|
||||
|
||||
@GetMapping("/contributors")
|
||||
public CommonResult<List<Contributor>> contributors() {
|
||||
return demoFeignClient.contributors("OpenFeign", "feign");
|
||||
}
|
||||
|
||||
@GetMapping("/reposNotFound")
|
||||
public CommonResult<List<Contributor>> reposNotFound() {
|
||||
return demoFeignClient.reposNotFound("OpenFeign", "feign");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.lingniu.demo.microservice;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Contributor {
|
||||
String login;
|
||||
int contributions;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.lingniu.demo.microservice;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.base.CommonResult;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = "lingniu-framework-provider-demo"
|
||||
//外部接口配置url: @FeignClient(name = "github-api", url = "https://api.github.com"
|
||||
// 方式1 配置fallback
|
||||
// , fallback = GithubApiClientFallBack.class
|
||||
// 方式2 配置fallbackFactory
|
||||
// , fallbackFactory = GithubApiClientFallbackFactory.class
|
||||
)
|
||||
public interface DemoFeignClient {
|
||||
|
||||
@GetMapping("/repos/{owner}/{repo}/contributors")
|
||||
CommonResult<List<Contributor>> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo);
|
||||
|
||||
@GetMapping("/reposNotFound")
|
||||
CommonResult<List<Contributor>> reposNotFound(@RequestParam("owner") String owner, @RequestParam("repo") String repo);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.lingniu.demo.microservice;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.base.CommonResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GithubApiClientFallBack implements DemoFeignClient {
|
||||
|
||||
@Override
|
||||
public CommonResult<List<Contributor>> contributors(String owner, String repo) {
|
||||
throw new RuntimeException("contributors no fallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<Contributor>> reposNotFound(String owner, String repo) {
|
||||
log.info("reposNotFoundWithFallBack");
|
||||
return CommonResult.success(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.lingniu.demo.microservice;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.exception.ServerException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GithubApiClientFallbackFactory implements FallbackFactory<GithubApiClientFallBack> {
|
||||
@Override
|
||||
public GithubApiClientFallBack create(Throwable cause) {
|
||||
if (cause instanceof ServerException) {
|
||||
return new GithubApiClientFallBack();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.lingniu.demo.monitor;
|
||||
|
||||
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusCounter;
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusMetrics;
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusSummary;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* http://localhost:30290/actuator
|
||||
* 访问 http://localhost:30290/actuator/metrics/metricName 查看指标
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/demo/prometheus")
|
||||
public class PrometheusController {
|
||||
|
||||
/**
|
||||
*
|
||||
Counter(计数器)
|
||||
Counter 是最简单的指标类型,它是一个单调递增的计数器,只能增加或重置为 0。通常用于记录请求总数、任务完成数、错误数等累计数据 */
|
||||
@GetMapping("/prometheusCounter")
|
||||
@PrometheusCounter( labels = {"prometheusCounter","test"}, memo = "prometheusCounter")
|
||||
public String prometheusCounter() {
|
||||
return "prometheusCounter";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
DistributionSummary(分布摘要)
|
||||
DistributionSummary 与 Histogram 类似,也用于测量数值的分布情况,但它专门用于跟踪事件的大小或持续时间等非时间性指标
|
||||
*/
|
||||
@GetMapping("/prometheusSummary")
|
||||
@PrometheusSummary(labels = {"prometheusSummary","test"}, memo = "prometheusSummary")
|
||||
public String prometheusSummary() {
|
||||
return "prometheusSummary";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Histogram(直方图)
|
||||
Histogram 用于测量数据的分布情况,如请求延迟、响应大小等。它会统计样本数据的分布情况,并提供分位数计算功能。
|
||||
*/
|
||||
@GetMapping("/PrometheusMetrics")
|
||||
@PrometheusMetrics(name = "prometheusMetrics")
|
||||
public String prometheusMetrics() {
|
||||
return "prometheusMetrics";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 自定义埋点
|
||||
*/
|
||||
@GetMapping("/selfMonitor")
|
||||
public String selfMonitor() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
Counter counter = Metrics.counter("selfMonitorCount", "selfMonitor", "selfMonitorCount");
|
||||
counter.increment();
|
||||
|
||||
DistributionSummary distributionSummary = Metrics.summary("selfMonitorSummary", "selfMonitor", "selfMonitorSummary");
|
||||
distributionSummary.record(System.currentTimeMillis() - startTime);
|
||||
|
||||
|
||||
return "selfMonitor";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* throw 异常 测试
|
||||
*/
|
||||
@GetMapping("/throw")
|
||||
public String throwEx() {
|
||||
throw new RuntimeException("test");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package cn.lingniu.demo.redisson;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonLockAction;
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonLockType;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LockActionDemo {
|
||||
|
||||
|
||||
@RedissonLockAction(redissonName = "r1", lockType = RedissonLockType.REENTRANT_LOCK,
|
||||
waitTime = 3000L, leaseTime = 30000L, unit = TimeUnit.MILLISECONDS,
|
||||
throwException = true)
|
||||
public void testLockAction(String test) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 #orderId 参数作为锁的key
|
||||
*/
|
||||
@PostMapping("/process/{orderId}")
|
||||
@RedissonLockAction(
|
||||
redissonName = "r1",
|
||||
key = "#orderId",
|
||||
lockType = RedissonLockType.REENTRANT_LOCK,
|
||||
waitTime = 3000L, leaseTime = 30000L, unit = TimeUnit.MILLISECONDS,
|
||||
throwException = true
|
||||
)
|
||||
public ResponseEntity<String> processOrder(@PathVariable String orderId) {
|
||||
// 业务逻辑
|
||||
return ResponseEntity.ok("Order processed: " + orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用请求参数
|
||||
*/
|
||||
@GetMapping("/query")
|
||||
@RedissonLockAction(
|
||||
redissonName = "defaultRedisson",
|
||||
key = "'query:' + #userId + ':' + #status",
|
||||
throwException = true
|
||||
)
|
||||
public ResponseEntity<List<Order>> queryOrders(
|
||||
@RequestParam String userId,
|
||||
@RequestParam String status) {
|
||||
// 业务逻辑
|
||||
return ResponseEntity.ok(new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用多个参数组合生成key
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
@RedissonLockAction(
|
||||
redissonName = "defaultRedisson",
|
||||
key = "'order:' + #orderDTO.orderId + ':user:' + #orderDTO.userId",
|
||||
waitTime = 5000L
|
||||
)
|
||||
public ResponseEntity<String> updateOrder(@RequestBody OrderDTO orderDTO) {
|
||||
// 业务逻辑
|
||||
return ResponseEntity.ok("Order updated");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class OrderDTO {
|
||||
private String orderId;
|
||||
private String userId;
|
||||
private String status;
|
||||
|
||||
// getters and setters
|
||||
public String getOrderId() { return orderId; }
|
||||
public void setOrderId(String orderId) { this.orderId = orderId; }
|
||||
public String getUserId() { return userId; }
|
||||
public void setUserId(String userId) { this.userId = userId; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package cn.lingniu.demo.redisson;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClientFactory;
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClusterLockerService;
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonLockAction;
|
||||
import org.redisson.api.RBucket;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RTopic;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 包含分布式锁和集群操作
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/demo/redisson")
|
||||
public class RedissonLockControllerDemo {
|
||||
|
||||
@Autowired
|
||||
RedissonClusterLockerService redissonClusterLockerService;
|
||||
//指定数据源:r1
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
public RedissonLockControllerDemo() {
|
||||
this.redissonClient = RedissonClientFactory.getRedissonClient("r1");
|
||||
}
|
||||
|
||||
@GetMapping("/lock")
|
||||
public String acquireLock(
|
||||
@RequestParam String lockName,
|
||||
@RequestParam long leaseTime
|
||||
) {
|
||||
RLock lock = redissonClient.getLock(lockName);
|
||||
try {
|
||||
boolean isLocked = lock.tryLock(5, leaseTime, TimeUnit.SECONDS);
|
||||
if (isLocked) {
|
||||
return "锁获取成功";
|
||||
} else {
|
||||
return "锁获取失败";
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return "锁获取异常";
|
||||
} finally {
|
||||
if (lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/bucket/set")
|
||||
public String setBucketValue(
|
||||
@RequestParam String key,
|
||||
@RequestParam String value
|
||||
) {
|
||||
RBucket<String> bucket = redissonClient.getBucket(key);
|
||||
bucket.set(value);
|
||||
return "键值设置成功";
|
||||
}
|
||||
|
||||
@GetMapping("/bucket/get/{key}")
|
||||
public String getBucketValue(@PathVariable String key) {
|
||||
RBucket<String> bucket = redissonClient.getBucket(key);
|
||||
return "结果:key:" + key + ",value:=" + bucket.get();
|
||||
}
|
||||
|
||||
@GetMapping("/topic/publish")
|
||||
public String publishMessage( @RequestParam String topicName,
|
||||
@RequestParam String message
|
||||
) {
|
||||
RTopic topic = redissonClient.getTopic(topicName);
|
||||
topic.publish(message);
|
||||
return "消息发布成功";
|
||||
}
|
||||
|
||||
@GetMapping("/lockAction")
|
||||
@RedissonLockAction(redissonName = "r1")
|
||||
public String redisson() {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return "lockAction";
|
||||
}
|
||||
|
||||
@GetMapping("/redissonClusterLockerService")
|
||||
public String redissonClusterLockerService() {
|
||||
return redissonClusterLockerService.wrapLock(this,
|
||||
x -> "r1", x -> "key1",
|
||||
x -> "success");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.lingniu.demo.rocketmq;
|
||||
|
||||
import cn.lingniu.demo.jetcache.controller.KeyValueEntity;
|
||||
import cn.lingniu.framework.plugin.rocketmq.core.producer.RocketMqSendMsgBody;
|
||||
import cn.lingniu.framework.plugin.rocketmq.core.producer.call.SendMessageOnFail;
|
||||
import cn.lingniu.framework.plugin.rocketmq.core.producer.call.SendMessageOnSuccess;
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/demo/rocketmq")
|
||||
public class RocketMqController {
|
||||
|
||||
@Autowired
|
||||
TestMqProducer testProducer;
|
||||
|
||||
@Autowired
|
||||
TestTransMqProducer testTransProducer;
|
||||
|
||||
@GetMapping("/test")
|
||||
public String test() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
KeyValueEntity body = new KeyValueEntity();
|
||||
String id = UUID.randomUUID().toString();
|
||||
body.setId(id);
|
||||
body.setKey("key" + id);
|
||||
body.setValue("value" + id);
|
||||
|
||||
RocketMqSendMsgBody<KeyValueEntity> message = new RocketMqSendMsgBody<>();
|
||||
message.setBody(body);
|
||||
if (i > 5) {
|
||||
message.setDelayLevel(1);
|
||||
}
|
||||
SendResult sendResult = testProducer.syncSend(message);
|
||||
System.out.println(sendResult);
|
||||
|
||||
testProducer.asyncSend(message, new SendMessageOnSuccess<KeyValueEntity>() {
|
||||
@Override
|
||||
public void call(KeyValueEntity message, SendResult result) {
|
||||
System.out.println(result);
|
||||
}
|
||||
}, new SendMessageOnFail<KeyValueEntity>() {
|
||||
@Override
|
||||
public void call(KeyValueEntity message, Throwable ex) {
|
||||
System.out.println(ex);
|
||||
}
|
||||
});
|
||||
|
||||
testTransProducer.syncSendInTransaction(message, null);
|
||||
}
|
||||
return "over";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.lingniu.demo.rocketmq;
|
||||
|
||||
import cn.lingniu.demo.jetcache.controller.KeyValueEntity;
|
||||
import cn.lingniu.framework.plugin.rocketmq.RocketMqConsumer;
|
||||
import cn.lingniu.framework.plugin.rocketmq.core.consumer.listener.RocketMqListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
|
||||
/**
|
||||
* 消费测试
|
||||
*/
|
||||
@Slf4j
|
||||
@RocketMqConsumer("consumer1")
|
||||
public class TestC1Consumer implements RocketMqListener<KeyValueEntity> {
|
||||
|
||||
@Override
|
||||
public void onMessage(KeyValueEntity message, MessageExt messageExt) {
|
||||
log.info("message{}", message);
|
||||
log.info("messageExt{}", messageExt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.lingniu.demo.rocketmq;
|
||||
|
||||
import cn.lingniu.demo.jetcache.controller.KeyValueEntity;
|
||||
import cn.lingniu.framework.plugin.rocketmq.RocketMqProducer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 普通生产者
|
||||
*/
|
||||
@Component
|
||||
public class TestMqProducer extends RocketMqProducer<KeyValueEntity> {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.lingniu.demo.rocketmq;
|
||||
|
||||
import cn.lingniu.demo.jetcache.controller.KeyValueEntity;
|
||||
import cn.lingniu.framework.plugin.rocketmq.RocketMqProducer;
|
||||
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
||||
import org.apache.rocketmq.client.producer.TransactionListener;
|
||||
import org.apache.rocketmq.common.message.Message;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 事物消息
|
||||
*/
|
||||
@Component
|
||||
public class TestTransMqProducer extends RocketMqProducer<KeyValueEntity> implements TransactionListener {
|
||||
|
||||
private AtomicInteger transactionIndex = new AtomicInteger(0);
|
||||
|
||||
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
|
||||
int value = transactionIndex.getAndIncrement();
|
||||
int status = value % 3;
|
||||
localTrans.put(message.getTransactionId(), status);
|
||||
return LocalTransactionState.UNKNOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
|
||||
Integer status = localTrans.get(messageExt.getTransactionId());
|
||||
if (null != status) {
|
||||
switch (status) {
|
||||
case 0 :
|
||||
return LocalTransactionState.UNKNOW;
|
||||
case 1 :
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
case 2 :
|
||||
return LocalTransactionState.ROLLBACK_MESSAGE;
|
||||
default:
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
}
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.lingniu.demo.web;
|
||||
|
||||
|
||||
import cn.lingniu.framework.plugin.core.base.CommonResult;
|
||||
import cn.lingniu.framework.plugin.web.apilog.ApiAccessLog;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/demo/web")
|
||||
public class WebController {
|
||||
|
||||
|
||||
@GetMapping("/errorResult")
|
||||
public WebEntity testRrrorResult() {
|
||||
WebEntity webEntity = new WebEntity();
|
||||
webEntity.setId(1L);
|
||||
webEntity.setName("error");
|
||||
webEntity.setEmail("<EMAIL>");
|
||||
return webEntity;
|
||||
}
|
||||
|
||||
@GetMapping("/commonResult")
|
||||
public CommonResult<WebEntity> test() {
|
||||
WebEntity webEntity = new WebEntity();
|
||||
webEntity.setId(1L);
|
||||
webEntity.setName("lingniu");
|
||||
webEntity.setEmail("<EMAIL>");
|
||||
return CommonResult.success(webEntity);
|
||||
}
|
||||
|
||||
|
||||
@ApiAccessLog(responseEnable = true)
|
||||
@GetMapping("/apiLog")
|
||||
public CommonResult<WebEntity> apiLog() {
|
||||
WebEntity webEntity = new WebEntity();
|
||||
webEntity.setId(1L);
|
||||
webEntity.setName("lingniu");
|
||||
webEntity.setEmail("<EMAIL>");
|
||||
return CommonResult.success(webEntity);
|
||||
}
|
||||
|
||||
|
||||
@ApiAccessLog(responseEnable = true)
|
||||
@GetMapping("/apiEncrypt")
|
||||
public CommonResult<WebEntity> apiEncrypt() {
|
||||
WebEntity webEntity = new WebEntity();
|
||||
webEntity.setId(1L);
|
||||
webEntity.setName("lingniu");
|
||||
webEntity.setEmail("<EMAIL>");
|
||||
return CommonResult.success(webEntity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package cn.lingniu.demo.web;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WebEntity {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String email;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
framework:
|
||||
lingniu:
|
||||
# 框架数据源配置
|
||||
datasource:
|
||||
# 开启框架 sql执行分析
|
||||
# dev,local,lpt,fat,test,uat,sit 这些环境可开启
|
||||
sqlLog: true
|
||||
# druid 后台地址:http://localhost:8080/druid/login.html
|
||||
# druid 账号,默认值为 SpringApplicationProperties#name
|
||||
druidUsername: "your_druid_username"
|
||||
# druid 密码,默认值为 SpringApplicationProperties#name + "123"
|
||||
druidPassword: "your_druid_password"
|
||||
@@ -0,0 +1,58 @@
|
||||
framework:
|
||||
lingniu:
|
||||
jetcache:
|
||||
# 需要隐藏的包路径(数组),默认为空
|
||||
hiddenPackages: [ ]
|
||||
# 统计信息输出间隔(分钟),默认为 0(不输出)
|
||||
statIntervalMinutes: 10
|
||||
# 是否在缓存名称中包含区域(area)信息,默认为 true
|
||||
areaInCacheName: true
|
||||
# 是否开启缓存穿透保护,默认为 false
|
||||
penetrationProtect: false
|
||||
# 本地缓存配置
|
||||
local:
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
ca2:
|
||||
# 本地缓存实现类类型,支持:linkedhashmap/caffeine
|
||||
type: linkedhashmap
|
||||
# 缓存key数量限制, 默认100
|
||||
limit: 100
|
||||
default:
|
||||
# 本地缓存实现类类型,支持:linkedhashmap/caffeine
|
||||
type: caffeine
|
||||
# 缓存key数量限制, 默认100
|
||||
limit: 100
|
||||
# 过期时间,0为不失效
|
||||
expireAfterAccessInMillis: 0
|
||||
# key 转换器,用于序列化,目前支持:NONE、FASTJSON、JACKSON、FASTJSON2
|
||||
keyConvertor: FASTJSON2
|
||||
remote:
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
ca2:
|
||||
# 远程缓存实现类类型,目前支持:redisson
|
||||
type: redisson
|
||||
# 远程缓存客户端名称,默认r1 -- todo 需要在application-redisson.yml中配置
|
||||
redissonClient: r1
|
||||
# key 前缀
|
||||
keyPrefix: "cacheKeyPrefix:"
|
||||
# 连接超时时间ms
|
||||
timeout: 2000
|
||||
# 重试次数
|
||||
maxAttempt: 5
|
||||
# 连接池配置
|
||||
poolConfig:
|
||||
maxTotal: 8
|
||||
maxIdle: 8
|
||||
minIdle: 0
|
||||
# key 转换器,用于序列化,目前支持:NONE、FASTJSON、JACKSON、FASTJSON2
|
||||
keyConvertor: FASTJSON2
|
||||
# JAVA, KRYO,KRYO5,自定义spring beanName
|
||||
valueEncoder: JAVA
|
||||
# JAVA, KRYO,KRYO5,自定义spring beanName
|
||||
valueDecoder: JAVA
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
default:
|
||||
# 远程缓存实现类类型,目前支持:redisson
|
||||
type: redisson
|
||||
# 远程缓存客户端名称,默认r1 -- todo 需要在application-redisson.yml中配置
|
||||
redissonClient: r1
|
||||
@@ -0,0 +1,6 @@
|
||||
framework:
|
||||
lingniu:
|
||||
prometheus:
|
||||
enabled: true
|
||||
port: 30290
|
||||
allowAssignPort: false
|
||||
@@ -0,0 +1,44 @@
|
||||
framework:
|
||||
lingniu:
|
||||
redisson:
|
||||
remote:
|
||||
r1:
|
||||
# 应用id需在cachecloud申请
|
||||
redisAddresses: 10.130.36.242:6387
|
||||
# 客户端名称,默认为应用名 + IP
|
||||
clientName: ""
|
||||
# 单节点 Redis 默认数据库,默认为 0
|
||||
database: 0
|
||||
# 连接池最小空闲连接数,默认为 12
|
||||
connectionMinimumIdleSize: 12
|
||||
# 连接池最大连接数,默认为 32
|
||||
connectionPoolSize: 32
|
||||
# 空闲连接超时时间(毫秒),默认为 10000
|
||||
idleConnectionTimeout: 10000
|
||||
# 连接超时时间(毫秒),默认为 2000
|
||||
connectTimeout: 2000
|
||||
# 操作超时时间(毫秒),默认为 2000
|
||||
timeout: 2000
|
||||
# 操作重试次数,默认为 4
|
||||
retryAttempts: 4
|
||||
# 集群模式下是否检查 Slots 覆盖,默认为 true
|
||||
checkSlotsCoverage: true
|
||||
# 读取模式,默认为 "SLAVE"
|
||||
# 可选值:
|
||||
# - SLAVE: 从节点读取
|
||||
# - MASTER: 主节点读取
|
||||
# - MASTER_SLAVE: 主从节点读取
|
||||
readMode: "SLAVE"
|
||||
# 存储类型,默认为 "CLUSTER"
|
||||
# 可选值:
|
||||
# - CLUSTER: 集群模式
|
||||
# - SINGLE: 单节点模式
|
||||
# - SENTINEL: 哨兵模式
|
||||
# - REPLICATED: 复制模式
|
||||
storageType: "CLUSTER"
|
||||
# 实例名称
|
||||
r2:
|
||||
# 应用id需在cachecloud申请
|
||||
redisAddresses: 10.130.36.242:6387
|
||||
# 单节点 Redis 默认数据库,默认为 0
|
||||
database: 0
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
framework:
|
||||
lingniu:
|
||||
# rocketmq所有配置示例
|
||||
rocketmq:
|
||||
# 是否开启数据源加密
|
||||
encryptEnabled: false
|
||||
# 消费者配置
|
||||
consumers:
|
||||
# 消费者bean名称
|
||||
TestC1Consumer:
|
||||
nameServer: mq_test_n1.tst.mid:9876
|
||||
# 消费组
|
||||
consumerGroup: consumer1
|
||||
# 消费对象名字
|
||||
consumerBeanName: TestC1Consumer
|
||||
# Topic
|
||||
topic: test1-yw-topic
|
||||
# 订阅表达式,默认为 *
|
||||
selectorExpress: "*"
|
||||
# 消费者最小线程数
|
||||
consumeThreadMin: 20
|
||||
# 消费者最大线程数
|
||||
consumeThreadMax: 32
|
||||
# 批量消费数量
|
||||
consumeMessageBatchMaxSize: 1
|
||||
# 批量拉取消息数量
|
||||
pullBatchSize: 32
|
||||
# 消息的最大重试次数
|
||||
maxRetryTimes: 16
|
||||
|
||||
# 生产者配置
|
||||
producers:
|
||||
# 生产者的bean名称
|
||||
TestMqProducer:
|
||||
nameServer: mq_test_n1.tst.mid:9876
|
||||
# 生产者组
|
||||
group: test1-yw-topic-producer
|
||||
# 生产端Topic
|
||||
topic: test1-yw-topic
|
||||
# 发送超时(ms),默认 3000
|
||||
sendMsgTimeout: 3000
|
||||
# 消息体压缩阀值(kb),默认 4096
|
||||
compressMsgBodyOverHowmuch: 4096
|
||||
# 同步发送消息失败,是否重新发送,默认 2
|
||||
retryTimesWhenSendFailed: 2
|
||||
# 异步发送消息失败,是否重新发送,默认 2
|
||||
retryTimesWhenSendAsyncFailed: 2
|
||||
# 重试另一个Broker当发送消息失败, 默认 false
|
||||
retryAnotherBrokerWhenNotStoreOk: false
|
||||
# 默认不启用延迟容错,通过统计每个队列的发送耗时情况来计算broker是否可用
|
||||
sendLatencyFaultEnable: false
|
||||
TestTransMqProducer:
|
||||
group: test1-yw-trans-topic-producer
|
||||
topic: test1-yw-trans-topic
|
||||
# 是否事务型
|
||||
isTransactionMQ: true
|
||||
# 事务消息线程配置
|
||||
transaction:
|
||||
corePoolSize: 5
|
||||
# 本地事务执行结果查询线程池配置
|
||||
maximumPoolSize: 10
|
||||
keepAliveTime: 200
|
||||
queueCapacity: 2000
|
||||
@@ -0,0 +1,12 @@
|
||||
framework:
|
||||
lingniu:
|
||||
web:
|
||||
apiLog:
|
||||
#开关
|
||||
enable: true
|
||||
apiEncrypt:
|
||||
#开关
|
||||
enable: false
|
||||
algorithm: "AES"
|
||||
requestKey: "xxx"
|
||||
responseKey: "xxx"
|
||||
@@ -0,0 +1,21 @@
|
||||
framework:
|
||||
lingniu:
|
||||
# XXL-JOB 配置
|
||||
xxljob:
|
||||
# 调度中心配置
|
||||
admin:
|
||||
# 调度中心部署根地址(多个地址用逗号分隔,为空则关闭自动注册)
|
||||
adminAddresses: "http://10.130.119.181:8099/xxl-job-admin"
|
||||
# 调度中心通讯TOKEN(非空时启用)
|
||||
accessToken: "default_token"
|
||||
|
||||
# 执行器配置
|
||||
executor:
|
||||
# 执行器IP(默认为空表示自动获取IP)
|
||||
ip: ""
|
||||
# 执行器端口号(小于等于0则自动获取,默认9999)
|
||||
port: 9999
|
||||
# 执行器日志文件保存天数(大于等于3时生效,-1表示关闭自动清理,默认7天)
|
||||
logRetentionDays: 7
|
||||
# 执行器运行日志文件存储磁盘路径(需对该路径拥有读写权限,为空则使用默认路径)
|
||||
logPath: logs/applogs/xxl-job/jobhandler
|
||||
@@ -0,0 +1,48 @@
|
||||
spring:
|
||||
application:
|
||||
name: lingniu-framework-demo
|
||||
profiles:
|
||||
active: dev,redisson,jetcache,xxljob,db,rocketmq,prometheus,web
|
||||
cloud:
|
||||
nacos:
|
||||
enabled: true #开启微服务自定义注册,自动获取当前框架信息,启动时间等到metadata中
|
||||
discovery:
|
||||
server-addr: http://nacos-uat-new-inter.xx.net.cn:8848 #注册中心地址
|
||||
username: nacos_test #注册中心用户名
|
||||
password: nacos_test #注册中心密码
|
||||
|
||||
#todo db基本配置,连接池请参考:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
|
||||
datasource:
|
||||
dynamic:
|
||||
primary: master
|
||||
datasource:
|
||||
#如需连接mysql,需修改下面的配置
|
||||
master:
|
||||
driver-class-name: org.h2.Driver
|
||||
url: jdbc:h2:mem:testdb
|
||||
username: sa
|
||||
password: sa
|
||||
slaver:
|
||||
driver-class-name: org.h2.Driver
|
||||
url: jdbc:h2:mem:testdb
|
||||
username: sa
|
||||
password: sa
|
||||
# http://localhost:8080/h2-console 访问 h2 数据库 账号: sa/sa
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
|
||||
|
||||
# apollo 配置
|
||||
framework:
|
||||
lingniu:
|
||||
apollo:
|
||||
#namespaces必须配置,配置文件列表,以逗号分割
|
||||
namespaces: application,applicationTest
|
||||
# 是否开启 Apollo 配置,默认true
|
||||
enabled: true
|
||||
# appId 等于 spring.application.name,无需配置
|
||||
appId: lingniu-framework-demo
|
||||
# meta 地址,框架自动获取,无需配置
|
||||
meta: http://10.130.36.237:8180
|
||||
@@ -0,0 +1,22 @@
|
||||
apollo:
|
||||
demo:
|
||||
string-demo: "示例字符串"
|
||||
boolean-demo: true
|
||||
list-demo:
|
||||
- "元素1"
|
||||
- "元素2"
|
||||
- "元素3"
|
||||
set-demo:
|
||||
- "集合元素1"
|
||||
- "集合元素2"
|
||||
hash-demo:
|
||||
key1: "值1"
|
||||
key2: "值2"
|
||||
key3: "值3"
|
||||
hash-object-demo:
|
||||
obj1:
|
||||
test-objcet: "对象示例1"
|
||||
obj2:
|
||||
test-objcet: "对象示例2"
|
||||
object-demo:
|
||||
test-objcet: "对象示例"
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
|
||||
<contextName>logback</contextName>
|
||||
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
|
||||
<!-- <property name="log.path" value="/opt/application/config/logs"/>-->
|
||||
<property name="log.path" value="/Users/likobe/logs/"/>
|
||||
|
||||
<!--输出到控制台-->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<append>true</append>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 每天日志归档路径以及格式 -->
|
||||
<fileNamePattern>${log.path}/log-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>30MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<!--日志文件保留天数-->
|
||||
<maxHistory>7</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.mybatis" level="debug"/>
|
||||
|
||||
<springProfile name="dev">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
<springProfile name="test">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
<springProfile name="pro">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
|
||||
|
||||
</configuration>
|
||||
60
demo/lingniu-framework-provider-demo/pom.xml
Normal file
60
demo/lingniu-framework-provider-demo/pom.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>lingniu-framework-provider-demo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-nacos</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.lingniu.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@ComponentScan(basePackages = {"cn.lingniu.*"})
|
||||
@SpringBootApplication
|
||||
public class ProviderDemoApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ProviderDemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.lingniu.demo.web;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Contributor {
|
||||
String login;
|
||||
int contributions;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.lingniu.demo.web;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.base.CommonResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class GithubApiController {
|
||||
|
||||
@GetMapping("/repos/{owner}/{repo}/contributors")
|
||||
public CommonResult<List<Contributor>> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo) {
|
||||
// 模拟返回贡献者列表
|
||||
Contributor contributor1 = new Contributor("user1", 10);
|
||||
Contributor contributor2 = new Contributor("user2", 5);
|
||||
List<Contributor> response = new ArrayList<>();
|
||||
response.add(contributor1);
|
||||
response.add(contributor2);
|
||||
return CommonResult.success(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
framework:
|
||||
lingniu:
|
||||
web:
|
||||
apiLog:
|
||||
#开关
|
||||
enable: true
|
||||
spring:
|
||||
cloud:
|
||||
isOkHttp: false
|
||||
@@ -0,0 +1,15 @@
|
||||
server:
|
||||
port: 8081
|
||||
spring:
|
||||
application:
|
||||
name: lingniu-framework-provider-demo
|
||||
profiles:
|
||||
active: dev,web
|
||||
cloud:
|
||||
nacos:
|
||||
enabled: true #开启微服务自定义注册,自动获取当前框架信息,启动时间等到metadata中
|
||||
discovery:
|
||||
server-addr: http://nacos-uat-new-inter.xx.net.cn:8848 #注册中心地址
|
||||
username: nacos_test #注册中心用户名
|
||||
password: nacos_test #注册中心密码
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
|
||||
<contextName>logback</contextName>
|
||||
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
|
||||
<!-- <property name="log.path" value="/opt/application/config/logs"/>-->
|
||||
<property name="log.path" value="/Users/likobe/logs/"/>
|
||||
|
||||
<!--输出到控制台-->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<append>true</append>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 每天日志归档路径以及格式 -->
|
||||
<fileNamePattern>${log.path}/log-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>30MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<!--日志文件保留天数-->
|
||||
<maxHistory>7</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="org.mybatis" level="debug"/>
|
||||
|
||||
<springProfile name="dev">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
<springProfile name="test">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
<springProfile name="pro">
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
|
||||
|
||||
</configuration>
|
||||
14
framework.md
Normal file
14
framework.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## lingniu-framework 介绍
|
||||
- 是一个基于 SpringBoot/cloud、Apollo、Nacos 等开发的内部框架。
|
||||
## lingniu-framework 特点
|
||||
* 基于 Spring 完整的 MVC + ORM 支持。
|
||||
* 支持多数据源、分库分表和分布式事务。
|
||||
* 统一注册:支持Nacos作为注册中心,实现多配置、分群组、分命名空间、多业务模块的注册和发现功能;
|
||||
* 支持基于 Apollo 分布式配置中心
|
||||
* 完整的分布式缓存、分布式session、分布式锁支持
|
||||
* 多租户功能:集成Mybatis Plus
|
||||
* 组件(Mysql/Oracle/Redis/JetCache/XXLJob等)多租户友好支持
|
||||
* 消息中心:集成消息中间件RocketMQ,对业务进行异步处理;
|
||||
* 等等
|
||||
## 组件介绍
|
||||

|
||||
768
lingniu-framework-dependencies/pom.xml
Normal file
768
lingniu-framework-dependencies/pom.xml
Normal file
@@ -0,0 +1,768 @@
|
||||
<?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>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
|
||||
<properties>
|
||||
<framework.version>1.0.0-SNAPSHOT</framework.version>
|
||||
<apollo.version>1.7.0</apollo.version>
|
||||
<jsoup.version>1.9.2</jsoup.version>
|
||||
<tio.version>3.7.5.v20211028-RELEASE</tio.version>
|
||||
<commons-net.version>3.9.0</commons-net.version>
|
||||
<netty-socketio.version>1.7.14</netty-socketio.version>
|
||||
<bcprov.version>1.70</bcprov.version>
|
||||
<spring-cloud-alibaba.version>2021.0.6.1</spring-cloud-alibaba.version>
|
||||
<pf4j-version>3.1.0</pf4j-version>
|
||||
<jackson.version>2.18.0</jackson.version>
|
||||
<jackson-databind.version>2.18.0</jackson-databind.version>
|
||||
<hutool-version>5.8.38</hutool-version>
|
||||
<okhttp3.version>4.9.3</okhttp3.version>
|
||||
<spring-boot.version>2.7.18</spring-boot.version>
|
||||
<spring-cloud.version>2021.0.6</spring-cloud.version>
|
||||
<feign-core.version>11.10</feign-core.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<apache.commons.version>3.17.0</apache.commons.version>
|
||||
<apache.common.collections>3.2.2</apache.common.collections>
|
||||
<junit.version>4.13</junit.version>
|
||||
<java.version>1.8</java.version>
|
||||
<jose4j.version>0.6.4</jose4j.version>
|
||||
<javax.persistence.version>1.0.2</javax.persistence.version>
|
||||
<javax.validation.version>1.1.0.Final</javax.validation.version>
|
||||
<guava.version>27.0-jre</guava.version>
|
||||
<lombok.version>1.18.38</lombok.version>
|
||||
<druid.version>1.2.25</druid.version>
|
||||
<argLine>-Xmx1G</argLine>
|
||||
<jz.version>1.1.1</jz.version>
|
||||
<rocketmq.version>4.5.1</rocketmq.version>
|
||||
<!--plugin version -->
|
||||
<build-helper-maven-plugin.version>1.10</build-helper-maven-plugin.version>
|
||||
<exec-maven-plugin.version>1.5.0</exec-maven-plugin.version>
|
||||
<git-commit-id-plugin.version>2.2.3</git-commit-id-plugin.version>
|
||||
<maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
|
||||
<maven-assembly-plugin.version>2.6</maven-assembly-plugin.version>
|
||||
<maven-clean-plugin.version>2.6.1</maven-clean-plugin.version>
|
||||
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
|
||||
<maven-dependency-plugin.version>2.10</maven-dependency-plugin.version>
|
||||
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
|
||||
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
||||
<maven-enforcer-plugin.version>1.4</maven-enforcer-plugin.version>
|
||||
<maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version>
|
||||
<maven-install-plugin.version>2.5.2</maven-install-plugin.version>
|
||||
<!-- <maven-install-plugin.version>3.1.0</maven-install-plugin.version>-->
|
||||
<maven-invoker-plugin.version>1.10</maven-invoker-plugin.version>
|
||||
<maven-help-plugin.version>2.2</maven-help-plugin.version>
|
||||
<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
|
||||
<!-- <maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>-->
|
||||
<maven-javadoc-plugin.version>2.10.4</maven-javadoc-plugin.version>
|
||||
<maven-resources-plugin.version>2.7</maven-resources-plugin.version>
|
||||
<maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
|
||||
<maven-site-plugin.version>3.5.1</maven-site-plugin.version>
|
||||
<maven-source-plugin.version>2.4</maven-source-plugin.version>
|
||||
<maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>
|
||||
<maven-war-plugin.version>2.6</maven-war-plugin.version>
|
||||
<versions-maven-plugin.version>2.2</versions-maven-plugin.version>
|
||||
<logback.version>1.2.9</logback.version>
|
||||
<slf4j.version>1.7.32</slf4j.version>
|
||||
<jetcache.version>2.7.1</jetcache.version>
|
||||
<curator.client.version>2.13.0</curator.client.version>
|
||||
<quartz.version>2.2.1</quartz.version>
|
||||
<bootstrap-ui.version>1.9.6</bootstrap-ui.version>
|
||||
<xxl.job.version>2.3.0</xxl.job.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<!-- todo 不升级-->
|
||||
<nacos-client.version>1.4.2</nacos-client.version>
|
||||
<commons.io.version>2.16.0</commons.io.version>
|
||||
<mzlion-core.version>1.1.2</mzlion-core.version>
|
||||
<lettuce.version>6.4.2.RELEASE</lettuce.version>
|
||||
<jedis.version>3.7.1</jedis.version>
|
||||
<log4j.version>2.18.0</log4j.version>
|
||||
<easyexcel.version>4.0.3</easyexcel.version>
|
||||
<hessian.version>3.1.5</hessian.version>
|
||||
<plexus.container.default>2.1.1</plexus.container.default>
|
||||
<hutoll.version>5.8.38</hutoll.version>
|
||||
<pinyin.version>2.5.1</pinyin.version>
|
||||
<jsqlparser.version>4.5</jsqlparser.version>
|
||||
<mybatis-plus-boot-starter.version>3.5.3.2</mybatis-plus-boot-starter.version>
|
||||
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
|
||||
<dynamic-datasource-starter.version>4.2.0</dynamic-datasource-starter.version>
|
||||
<mybatis-spring.version>2.1.2</mybatis-spring.version>
|
||||
<mybatis.version>3.5.14</mybatis.version>
|
||||
<mybatis-spring-boot.version>2.3.2</mybatis-spring-boot.version>
|
||||
<pagehelper-starter.version>1.4.2</pagehelper-starter.version>
|
||||
<pagehelper.version>5.3.3</pagehelper.version>
|
||||
<dynamictp.version>1.1.5</dynamictp.version>
|
||||
<joda-time.version>2.13.0</joda-time.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-util</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-apollo</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-xxljob</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-mybatis</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-jetcache</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-redisson</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-rocketmq</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-skywalking</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-prometheus</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-web</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-common</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-microservice-nacos</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-easyexcel</artifactId>
|
||||
<version>${framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId>
|
||||
<version>${apollo.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--oracle start -->
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc14</artifactId>
|
||||
<version>10.2.0.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>${pagehelper.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.jsqlparser</groupId>
|
||||
<artifactId>jsqlparser</artifactId>
|
||||
<version>${jsqlparser.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-spring-boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<version>${mybatis-spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
<version>1.9.17</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>${lettuce.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ojdbc</groupId>
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
<version>11.2.0.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>${bcprov.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>one.util</groupId>
|
||||
<artifactId>streamex</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>jool</artifactId>
|
||||
<version>0.9.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId>
|
||||
<artifactId>pf4j</artifactId>
|
||||
<version>${pf4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- okhttp3 -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
<version>${hutool-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutoll.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.jfinal/jfinal -->
|
||||
<dependency>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>jfinal</artifactId>
|
||||
<version>4.8</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.jfinal/jfinal-weixin -->
|
||||
<dependency>
|
||||
<groupId>com.jfinal</groupId>
|
||||
<artifactId>jfinal-weixin</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/net.dreamlu/mica-auto -->
|
||||
<dependency>
|
||||
<groupId>net.dreamlu</groupId>
|
||||
<artifactId>mica-auto</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.unidal.framework</groupId>
|
||||
<artifactId>foundation-service</artifactId>
|
||||
<version>4.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>3.17.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.caucho</groupId>
|
||||
<artifactId>hessian</artifactId>
|
||||
<version>${hessian.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>${javax.persistence.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.db4j</groupId>
|
||||
<artifactId>reflectasm</artifactId>
|
||||
<version>1.11.4-2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-typehandlers-jsr310</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus-boot-starter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
<version>${mybatis-plus-boot-starter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
<version>${dynamic-datasource-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-tools</artifactId>
|
||||
<version>${rocketmq.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-client</artifactId>
|
||||
<version>${rocketmq.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${apache.commons.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>${apache.common.collections}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.2.5.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!--缓存-->
|
||||
<dependency>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
<artifactId>jetcache-anno</artifactId>
|
||||
<version>${jetcache.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>${xxl.job.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-parameter-names</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>${jsoup.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<version>${commons-net.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>3.24.1-GA</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-core</artifactId>
|
||||
<version>${feign-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.t-io</groupId>
|
||||
<artifactId>tio-core</artifactId>
|
||||
<version>${tio.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.t-io</groupId>
|
||||
<artifactId>tio-websocket-server</artifactId>
|
||||
<version>${tio.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>${spring-cloud-alibaba.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
<version>${nacos-client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-core</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>${mybatis.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-container-default</artifactId>
|
||||
<version>${plexus.container.default}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.collections</groupId>
|
||||
<artifactId>google-collections</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.belerweb</groupId>
|
||||
<artifactId>pinyin4j</artifactId>
|
||||
<version>${pinyin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.dynamictp</groupId>
|
||||
<artifactId>dynamic-tp-spring-boot-starter-apollo</artifactId>
|
||||
<version>${dynamictp.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>${maven-assembly-plugin.version}</version>
|
||||
<configuration>
|
||||
<recompressZippedFiles>false</recompressZippedFiles>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>${maven-clean-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>${maven-install-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-help-plugin</artifactId>
|
||||
<version>${maven-help-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${maven-resources-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>${maven-site-plugin.version}</version>
|
||||
</plugin>
|
||||
<!-- <plugin>-->
|
||||
<!-- <groupId>org.apache.maven.plugins</groupId>-->
|
||||
<!-- <artifactId>maven-source-plugin</artifactId>-->
|
||||
<!-- <version>${maven-source-plugin.version}</version>-->
|
||||
<!-- </plugin>-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>${build-helper-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
</build>
|
||||
</project>
|
||||
52
lingniu-framework-plugin/cache/lingniu-framework-plugin-jetcache/pom.xml
vendored
Normal file
52
lingniu-framework-plugin/cache/lingniu-framework-plugin-jetcache/pom.xml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-jetcache</artifactId>
|
||||
<name>lingniu-framework-plugin-jetcache</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
<artifactId>jetcache-anno</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,95 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.AbstractCacheBuilder;
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.anno.KeyConvertor;
|
||||
import com.alicp.jetcache.anno.support.ParserFunction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created on 2016/11/29.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public abstract class AbstractCacheAutoInit implements InitializingBean {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(AbstractCacheAutoInit.class);
|
||||
|
||||
@Autowired
|
||||
protected ConfigurableEnvironment environment;
|
||||
|
||||
@Autowired
|
||||
protected AutoConfigureBeans autoConfigureBeans;
|
||||
|
||||
protected String[] typeNames;
|
||||
|
||||
private volatile boolean inited = false;
|
||||
|
||||
public AbstractCacheAutoInit(String... cacheTypes) {
|
||||
Objects.requireNonNull(cacheTypes, "cacheTypes can't be null");
|
||||
Assert.isTrue(cacheTypes.length > 0, "cacheTypes length is 0");
|
||||
this.typeNames = cacheTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (!inited) {
|
||||
synchronized (this) {
|
||||
if (!inited) {
|
||||
process("framework.lingniu.jetcache.local.", autoConfigureBeans.getLocalCacheBuilders(), true);
|
||||
process("framework.lingniu.jetcache.remote.", autoConfigureBeans.getRemoteCacheBuilders(), false);
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void process(String prefix, Map cacheBuilders, boolean local) {
|
||||
ConfigTree resolver = new ConfigTree(environment, prefix);
|
||||
Map<String, Object> m = resolver.getProperties();
|
||||
Set<String> cacheAreaNames = resolver.directChildrenKeys();
|
||||
for (String cacheArea : cacheAreaNames) {
|
||||
final Object configType = m.get(cacheArea + ".type");
|
||||
boolean match = Arrays.stream(typeNames).anyMatch((tn) -> tn.equals(configType));
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
ConfigTree ct = resolver.subTree(cacheArea + ".");
|
||||
logger.info("init cache area {} , type= {}", cacheArea, typeNames[0]);
|
||||
CacheBuilder c = initCache(ct, local ? "local." + cacheArea : "remote." + cacheArea);
|
||||
cacheBuilders.put(cacheArea, c);
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseGeneralConfig(CacheBuilder builder, ConfigTree ct) {
|
||||
AbstractCacheBuilder acb = (AbstractCacheBuilder) builder;
|
||||
acb.keyConvertor(new ParserFunction(ct.getProperty("keyConvertor", KeyConvertor.FASTJSON2)));
|
||||
|
||||
String expireAfterWriteInMillis = ct.getProperty("expireAfterWriteInMillis");
|
||||
if (expireAfterWriteInMillis == null) {
|
||||
// compatible with 2.1
|
||||
expireAfterWriteInMillis = ct.getProperty("defaultExpireInMillis");
|
||||
}
|
||||
if (expireAfterWriteInMillis != null) {
|
||||
acb.setExpireAfterWriteInMillis(Long.parseLong(expireAfterWriteInMillis));
|
||||
}
|
||||
|
||||
String expireAfterAccessInMillis = ct.getProperty("expireAfterAccessInMillis");
|
||||
if (expireAfterAccessInMillis != null) {
|
||||
acb.setExpireAfterAccessInMillis(Long.parseLong(expireAfterAccessInMillis));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected abstract CacheBuilder initCache(ConfigTree ct, String cacheAreaWithPrefix);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created on 2016/12/28.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public class AutoConfigureBeans {
|
||||
|
||||
private Map<String, CacheBuilder> localCacheBuilders = new HashMap<>();
|
||||
|
||||
private Map<String, CacheBuilder> remoteCacheBuilders = new HashMap<>();
|
||||
|
||||
private Map<String, Object> customContainer = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public Map<String, CacheBuilder> getLocalCacheBuilders() {
|
||||
return localCacheBuilders;
|
||||
}
|
||||
|
||||
public void setLocalCacheBuilders(Map<String, CacheBuilder> localCacheBuilders) {
|
||||
this.localCacheBuilders = localCacheBuilders;
|
||||
}
|
||||
|
||||
public Map<String, CacheBuilder> getRemoteCacheBuilders() {
|
||||
return remoteCacheBuilders;
|
||||
}
|
||||
|
||||
public void setRemoteCacheBuilders(Map<String, CacheBuilder> remoteCacheBuilders) {
|
||||
this.remoteCacheBuilders = remoteCacheBuilders;
|
||||
}
|
||||
|
||||
public Map<String, Object> getCustomContainer() {
|
||||
return customContainer;
|
||||
}
|
||||
|
||||
public void setCustomContainer(Map<String, Object> customContainer) {
|
||||
this.customContainer = customContainer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created on 2017/5/5.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public class BeanDependencyManager implements BeanFactoryPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
String[] autoInitBeanNames = beanFactory.getBeanNamesForType(AbstractCacheAutoInit.class, false, false);
|
||||
if (autoInitBeanNames != null) {
|
||||
BeanDefinition bd = beanFactory.getBeanDefinition(JetCacheAutoConfiguration.GLOBAL_CACHE_CONFIG_NAME);
|
||||
String[] dependsOn = bd.getDependsOn();
|
||||
if (dependsOn == null) {
|
||||
dependsOn = new String[0];
|
||||
}
|
||||
int oldLen = dependsOn.length;
|
||||
dependsOn = Arrays.copyOf(dependsOn, dependsOn.length + autoInitBeanNames.length);
|
||||
System.arraycopy(autoInitBeanNames, 0, dependsOn, oldLen, autoInitBeanNames.length);
|
||||
bd.setDependsOn(dependsOn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.embedded.CaffeineCacheBuilder;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created on 2016/12/2.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
@Component
|
||||
@Conditional(CaffeineAutoConfiguration.CaffeineCondition.class)
|
||||
public class CaffeineAutoConfiguration extends EmbeddedCacheAutoInit {
|
||||
public CaffeineAutoConfiguration() {
|
||||
super("caffeine");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheBuilder initCache(ConfigTree ct, String cacheAreaWithPrefix) {
|
||||
CaffeineCacheBuilder builder = CaffeineCacheBuilder.createCaffeineCacheBuilder();
|
||||
parseGeneralConfig(builder, ct);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static class CaffeineCondition extends JetCacheCondition {
|
||||
public CaffeineCondition() {
|
||||
super("caffeine");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created on 2017/11/20.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public class ConfigTree {
|
||||
private ConfigurableEnvironment environment;
|
||||
private String prefix;
|
||||
|
||||
public ConfigTree(ConfigurableEnvironment environment, String prefix) {
|
||||
Assert.notNull(environment, "environment is required");
|
||||
Assert.notNull(prefix, "prefix is required");
|
||||
this.environment = environment;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public ConfigTree subTree(String prefix) {
|
||||
return new ConfigTree(environment, fullPrefixOrKey(prefix));
|
||||
}
|
||||
|
||||
private String fullPrefixOrKey(String prefixOrKey) {
|
||||
return this.prefix + prefixOrKey;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
Map<String, Object> m = new HashMap<>();
|
||||
for (PropertySource<?> source : environment.getPropertySources()) {
|
||||
if (source instanceof EnumerablePropertySource) {
|
||||
for (String name : ((EnumerablePropertySource<?>) source)
|
||||
.getPropertyNames()) {
|
||||
if (name != null && name.startsWith(prefix)) {
|
||||
String subKey = name.substring(prefix.length());
|
||||
m.put(subKey, environment.getProperty(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean containsProperty(String key) {
|
||||
key = fullPrefixOrKey(key);
|
||||
return environment.containsProperty(key);
|
||||
}
|
||||
|
||||
public String getProperty(String key) {
|
||||
key = fullPrefixOrKey(key);
|
||||
return environment.getProperty(key);
|
||||
}
|
||||
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
if (containsProperty(key)) {
|
||||
return getProperty(key);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getProperty(String key, boolean defaultValue) {
|
||||
if (containsProperty(key)) {
|
||||
return Boolean.parseBoolean(getProperty(key));
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public int getProperty(String key, int defaultValue) {
|
||||
if (containsProperty(key)) {
|
||||
return Integer.parseInt(getProperty(key));
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public long getProperty(String key, long defaultValue) {
|
||||
if (containsProperty(key)) {
|
||||
return Long.parseLong(getProperty(key));
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public Set<String> directChildrenKeys() {
|
||||
Map<String, Object> m = getProperties();
|
||||
return m.keySet().stream().map(
|
||||
s -> s.indexOf('.') >= 0 ? s.substring(0, s.indexOf('.')) : null)
|
||||
.filter(s -> s != null)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.anno.CacheConsts;
|
||||
import com.alicp.jetcache.embedded.EmbeddedCacheBuilder;
|
||||
|
||||
/**
|
||||
* Created on 2016/12/2.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public abstract class EmbeddedCacheAutoInit extends AbstractCacheAutoInit {
|
||||
|
||||
public EmbeddedCacheAutoInit(String... cacheTypes) {
|
||||
super(cacheTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseGeneralConfig(CacheBuilder builder, ConfigTree ct) {
|
||||
super.parseGeneralConfig(builder, ct);
|
||||
EmbeddedCacheBuilder ecb = (EmbeddedCacheBuilder) builder;
|
||||
|
||||
ecb.limit(Integer.parseInt(ct.getProperty("limit", String.valueOf(CacheConsts.DEFAULT_LOCAL_LIMIT))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.anno.CacheConsts;
|
||||
import com.alicp.jetcache.anno.support.ParserFunction;
|
||||
import com.alicp.jetcache.external.ExternalCacheBuilder;
|
||||
|
||||
/**
|
||||
* Created on 2016/11/29.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public abstract class ExternalCacheAutoInit extends AbstractCacheAutoInit {
|
||||
public ExternalCacheAutoInit(String... cacheTypes) {
|
||||
super(cacheTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseGeneralConfig(CacheBuilder builder, ConfigTree ct) {
|
||||
super.parseGeneralConfig(builder, ct);
|
||||
ExternalCacheBuilder ecb = (ExternalCacheBuilder) builder;
|
||||
ecb.setKeyPrefix(ct.getProperty("keyPrefix"));
|
||||
ecb.setBroadcastChannel(parseBroadcastChannel(ct));
|
||||
ecb.setValueEncoder(new ParserFunction(ct.getProperty("valueEncoder", CacheConsts.DEFAULT_SERIAL_POLICY)));
|
||||
ecb.setValueDecoder(new ParserFunction(ct.getProperty("valueDecoder", CacheConsts.DEFAULT_SERIAL_POLICY)));
|
||||
}
|
||||
|
||||
protected String parseBroadcastChannel(ConfigTree ct) {
|
||||
String broadcastChannel = ct.getProperty("broadcastChannel");
|
||||
if (broadcastChannel != null && !"".equals(broadcastChannel.trim())) {
|
||||
return broadcastChannel.trim();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheManager;
|
||||
import com.alicp.jetcache.SimpleCacheManager;
|
||||
import com.alicp.jetcache.anno.support.EncoderParser;
|
||||
import com.alicp.jetcache.anno.support.GlobalCacheConfig;
|
||||
import com.alicp.jetcache.anno.support.JetCacheBaseBeans;
|
||||
import com.alicp.jetcache.anno.support.KeyConvertorParser;
|
||||
import com.alicp.jetcache.anno.support.SpringConfigProvider;
|
||||
import com.alicp.jetcache.support.StatInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Created on 2016/11/17.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(GlobalCacheConfig.class)
|
||||
@ConditionalOnMissingBean(GlobalCacheConfig.class)
|
||||
@EnableConfigurationProperties(JetCacheProperties.class)
|
||||
@Import({CaffeineAutoConfiguration.class,
|
||||
MockRemoteCacheAutoConfiguration.class,
|
||||
LinkedHashMapAutoConfiguration.class,
|
||||
RedissonAutoConfiguration.class})
|
||||
public class JetCacheAutoConfiguration {
|
||||
|
||||
public static final String GLOBAL_CACHE_CONFIG_NAME = "globalCacheConfig";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SpringConfigProvider springConfigProvider(
|
||||
@Autowired ApplicationContext applicationContext,
|
||||
@Autowired GlobalCacheConfig globalCacheConfig,
|
||||
@Autowired(required = false) EncoderParser encoderParser,
|
||||
@Autowired(required = false) KeyConvertorParser keyConvertorParser,
|
||||
@Autowired(required = false) Consumer<StatInfo> metricsCallback) {
|
||||
return new JetCacheBaseBeans().springConfigProvider(applicationContext, globalCacheConfig,
|
||||
encoderParser, keyConvertorParser, metricsCallback);
|
||||
}
|
||||
|
||||
@Bean(name = "jcCacheManager")
|
||||
@ConditionalOnMissingBean
|
||||
public CacheManager cacheManager(@Autowired SpringConfigProvider springConfigProvider) {
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
cacheManager.setCacheBuilderTemplate(springConfigProvider.getCacheBuilderTemplate());
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AutoConfigureBeans autoConfigureBeans() {
|
||||
return new AutoConfigureBeans();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BeanDependencyManager beanDependencyManager() {
|
||||
return new BeanDependencyManager();
|
||||
}
|
||||
|
||||
@Bean(name = GLOBAL_CACHE_CONFIG_NAME)
|
||||
public GlobalCacheConfig globalCacheConfig(AutoConfigureBeans autoConfigureBeans, JetCacheProperties props) {
|
||||
GlobalCacheConfig _globalCacheConfig = new GlobalCacheConfig();
|
||||
_globalCacheConfig = new GlobalCacheConfig();
|
||||
_globalCacheConfig.setHiddenPackages(props.getHiddenPackages());
|
||||
_globalCacheConfig.setStatIntervalMinutes(props.getStatIntervalMinutes());
|
||||
_globalCacheConfig.setAreaInCacheName(props.isAreaInCacheName());
|
||||
_globalCacheConfig.setPenetrationProtect(props.isPenetrationProtect());
|
||||
_globalCacheConfig.setEnableMethodCache(props.isEnableMethodCache());
|
||||
_globalCacheConfig.setLocalCacheBuilders(autoConfigureBeans.getLocalCacheBuilders());
|
||||
_globalCacheConfig.setRemoteCacheBuilders(autoConfigureBeans.getRemoteCacheBuilders());
|
||||
return _globalCacheConfig;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created on 2016/11/28.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
public abstract class JetCacheCondition extends SpringBootCondition {
|
||||
|
||||
private String[] cacheTypes;
|
||||
|
||||
protected JetCacheCondition(String... cacheTypes) {
|
||||
Objects.requireNonNull(cacheTypes, "cacheTypes can't be null");
|
||||
Assert.isTrue(cacheTypes.length > 0, "cacheTypes length is 0");
|
||||
this.cacheTypes = cacheTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
|
||||
ConfigTree ct = new ConfigTree((ConfigurableEnvironment) conditionContext.getEnvironment(), "framework.lingniu.jetcache.");
|
||||
if (match(ct, "local.") || match(ct, "remote.")) {
|
||||
return ConditionOutcome.match();
|
||||
} else {
|
||||
return ConditionOutcome.noMatch("no match for " + cacheTypes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean match(ConfigTree ct, String prefix) {
|
||||
Map<String, Object> m = ct.subTree(prefix).getProperties();
|
||||
Set<String> cacheAreaNames = m.keySet().stream().map((s) -> s.substring(0, s.indexOf('.'))).collect(Collectors.toSet());
|
||||
final List<String> cacheTypesList = Arrays.asList(cacheTypes);
|
||||
return cacheAreaNames.stream().anyMatch((s) -> cacheTypesList.contains(m.get(s + ".type")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Created on 2016/11/23.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "jetcache")
|
||||
public class JetCacheProperties {
|
||||
|
||||
private String[] hiddenPackages;
|
||||
private int statIntervalMinutes;
|
||||
private boolean areaInCacheName = true;
|
||||
private boolean penetrationProtect = false;
|
||||
private boolean enableMethodCache = true;
|
||||
|
||||
public JetCacheProperties() {
|
||||
}
|
||||
|
||||
public String[] getHiddenPackages() {
|
||||
// keep same with GlobalCacheConfig
|
||||
return hiddenPackages;
|
||||
}
|
||||
|
||||
public void setHiddenPackages(String[] hiddenPackages) {
|
||||
// keep same with GlobalCacheConfig
|
||||
this.hiddenPackages = hiddenPackages;
|
||||
}
|
||||
|
||||
public void setHidePackages(String[] hidePackages) {
|
||||
// keep same with GlobalCacheConfig
|
||||
this.hiddenPackages = hidePackages;
|
||||
}
|
||||
|
||||
public int getStatIntervalMinutes() {
|
||||
return statIntervalMinutes;
|
||||
}
|
||||
|
||||
public void setStatIntervalMinutes(int statIntervalMinutes) {
|
||||
this.statIntervalMinutes = statIntervalMinutes;
|
||||
}
|
||||
|
||||
public boolean isAreaInCacheName() {
|
||||
return areaInCacheName;
|
||||
}
|
||||
|
||||
public void setAreaInCacheName(boolean areaInCacheName) {
|
||||
this.areaInCacheName = areaInCacheName;
|
||||
}
|
||||
|
||||
public boolean isPenetrationProtect() {
|
||||
return penetrationProtect;
|
||||
}
|
||||
|
||||
public void setPenetrationProtect(boolean penetrationProtect) {
|
||||
this.penetrationProtect = penetrationProtect;
|
||||
}
|
||||
|
||||
public boolean isEnableMethodCache() {
|
||||
return enableMethodCache;
|
||||
}
|
||||
|
||||
public void setEnableMethodCache(boolean enableMethodCache) {
|
||||
this.enableMethodCache = enableMethodCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.embedded.LinkedHashMapCacheBuilder;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created on 2016/12/2.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
@Component
|
||||
@Conditional(LinkedHashMapAutoConfiguration.LinkedHashMapCondition.class)
|
||||
public class LinkedHashMapAutoConfiguration extends EmbeddedCacheAutoInit {
|
||||
public LinkedHashMapAutoConfiguration() {
|
||||
super("linkedhashmap");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheBuilder initCache(ConfigTree ct, String cacheAreaWithPrefix) {
|
||||
LinkedHashMapCacheBuilder builder = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder();
|
||||
parseGeneralConfig(builder, ct);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static class LinkedHashMapCondition extends JetCacheCondition {
|
||||
public LinkedHashMapCondition() {
|
||||
super("linkedhashmap");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.anno.CacheConsts;
|
||||
import com.alicp.jetcache.external.MockRemoteCacheBuilder;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created on 2016/12/2.
|
||||
*
|
||||
* @author <a href="mailto:areyouok@gmail.com">huangli</a>
|
||||
*/
|
||||
@Component
|
||||
@Conditional(MockRemoteCacheAutoConfiguration.MockRemoteCacheCondition.class)
|
||||
public class MockRemoteCacheAutoConfiguration extends ExternalCacheAutoInit {
|
||||
public MockRemoteCacheAutoConfiguration() {
|
||||
super("mock");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheBuilder initCache(ConfigTree ct, String cacheAreaWithPrefix) {
|
||||
MockRemoteCacheBuilder builder = MockRemoteCacheBuilder.createMockRemoteCacheBuilder();
|
||||
parseGeneralConfig(builder, ct);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseGeneralConfig(CacheBuilder builder, ConfigTree ct) {
|
||||
super.parseGeneralConfig(builder, ct);
|
||||
MockRemoteCacheBuilder b = (MockRemoteCacheBuilder) builder;
|
||||
b.limit(Integer.parseInt(ct.getProperty("limit", String.valueOf(CacheConsts.DEFAULT_LOCAL_LIMIT))));
|
||||
}
|
||||
|
||||
public static class MockRemoteCacheCondition extends JetCacheCondition {
|
||||
public MockRemoteCacheCondition() {
|
||||
super("mock");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.autoconfigure;
|
||||
|
||||
import cn.lingniu.framework.plugin.jetcache.redisson.RedissonCacheBuilder;
|
||||
import com.alicp.jetcache.CacheBuilder;
|
||||
import com.alicp.jetcache.CacheConfigException;
|
||||
import com.alicp.jetcache.external.ExternalCacheBuilder;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Created on 2022/7/12.
|
||||
*
|
||||
* @author <a href="mailto:jeason1914@qq.com">yangyong</a>
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(RedissonAutoConfiguration.RedissonCondition.class)
|
||||
public class RedissonAutoConfiguration {
|
||||
private static final String CACHE_TYPE = "redisson";
|
||||
|
||||
public static class RedissonCondition extends JetCacheCondition {
|
||||
public RedissonCondition() {
|
||||
super(CACHE_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedissonAutoInit redissonAutoInit() {
|
||||
return new RedissonAutoInit();
|
||||
}
|
||||
|
||||
public static class RedissonAutoInit extends ExternalCacheAutoInit implements ApplicationContextAware {
|
||||
private ApplicationContext context;
|
||||
|
||||
public RedissonAutoInit() {
|
||||
super(CACHE_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheBuilder initCache(final ConfigTree ct, final String cacheAreaWithPrefix) {
|
||||
final Map<String, RedissonClient> beans = this.context.getBeansOfType(RedissonClient.class);
|
||||
if (beans.isEmpty()) {
|
||||
throw new CacheConfigException("no RedissonClient in spring context");
|
||||
}
|
||||
RedissonClient client = beans.values().iterator().next();
|
||||
if (beans.size() > 1) {
|
||||
final String redissonClientName = ct.getProperty("redissonClient");
|
||||
if (Objects.isNull(redissonClientName) || redissonClientName.isEmpty()) {
|
||||
throw new CacheConfigException("redissonClient is required, because there is multiple RedissonClient in Spring context");
|
||||
}
|
||||
if (!beans.containsKey(redissonClientName)) {
|
||||
throw new CacheConfigException("there is no RedissonClient named " + redissonClientName + " in Spring context");
|
||||
}
|
||||
client = beans.get(redissonClientName);
|
||||
}
|
||||
final ExternalCacheBuilder<?> builder = RedissonCacheBuilder.createBuilder().redissonClient(client);
|
||||
parseGeneralConfig(builder, ct);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(final ApplicationContext context) throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.redisson;
|
||||
|
||||
import com.alicp.jetcache.CacheManager;
|
||||
import com.alicp.jetcache.CacheResult;
|
||||
import com.alicp.jetcache.support.BroadcastManager;
|
||||
import com.alicp.jetcache.support.CacheMessage;
|
||||
import com.alicp.jetcache.support.SquashedLogger;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Created on 2022/7/12.
|
||||
*
|
||||
* @author <a href="mailto:jeason1914@qq.com">yangyong</a>
|
||||
*/
|
||||
public class RedissonBroadcastManager extends BroadcastManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RedissonBroadcastManager.class);
|
||||
private final RedissonCacheConfig<?, ?> config;
|
||||
private final String channel;
|
||||
private final RedissonClient client;
|
||||
private volatile int subscribeId;
|
||||
|
||||
public RedissonBroadcastManager(final CacheManager cacheManager, final RedissonCacheConfig<?, ?> config) {
|
||||
super(cacheManager);
|
||||
checkConfig(config);
|
||||
this.config = config;
|
||||
this.channel = config.getBroadcastChannel();
|
||||
this.client = config.getRedissonClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void startSubscribe() {
|
||||
if (this.subscribeId == 0 && Objects.nonNull(this.channel) && !this.channel.isEmpty()) {
|
||||
this.subscribeId = this.client.getTopic(this.channel)
|
||||
.addListener(byte[].class, (channel, msg) -> processNotification(msg, this.config.getValueDecoder()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
final int id;
|
||||
if ((id = this.subscribeId) > 0 && Objects.nonNull(this.channel)) {
|
||||
this.subscribeId = 0;
|
||||
try {
|
||||
this.client.getTopic(this.channel).removeListener(id);
|
||||
} catch (Throwable e) {
|
||||
logger.warn("unsubscribe {} fail", this.channel, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheResult publish(final CacheMessage cacheMessage) {
|
||||
try {
|
||||
if (Objects.nonNull(this.channel) && Objects.nonNull(cacheMessage)) {
|
||||
final byte[] msg = this.config.getValueEncoder().apply(cacheMessage);
|
||||
this.client.getTopic(this.channel).publish(msg);
|
||||
return CacheResult.SUCCESS_WITHOUT_MSG;
|
||||
}
|
||||
return CacheResult.FAIL_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
SquashedLogger.getLogger(logger).error("jetcache publish error", e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.redisson;
|
||||
|
||||
import com.alicp.jetcache.CacheConfig;
|
||||
import com.alicp.jetcache.CacheGetResult;
|
||||
import com.alicp.jetcache.CacheResult;
|
||||
import com.alicp.jetcache.CacheResultCode;
|
||||
import com.alicp.jetcache.CacheValueHolder;
|
||||
import com.alicp.jetcache.MultiGetResult;
|
||||
import com.alicp.jetcache.external.AbstractExternalCache;
|
||||
import org.redisson.api.RBatch;
|
||||
import org.redisson.api.RBucket;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Created on 2022/7/12.
|
||||
*
|
||||
* @author <a href="mailto:jeason1914@qq.com">yangyong</a>
|
||||
*/
|
||||
public class RedissonCache<K, V> extends AbstractExternalCache<K, V> {
|
||||
private final RedissonClient client;
|
||||
private final RedissonCacheConfig<K, V> config;
|
||||
|
||||
public RedissonCache(final RedissonCacheConfig<K, V> config) {
|
||||
super(config);
|
||||
this.config = config;
|
||||
this.client = config.getRedissonClient();
|
||||
}
|
||||
|
||||
protected String getCacheKey(final K key) {
|
||||
final byte[] newKey = buildKey(key);
|
||||
return new String(newKey, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheConfig<K, V> config() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(final Class<T> clazz) {
|
||||
throw new UnsupportedOperationException("RedissonCache does not support unwrap");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
protected CacheGetResult<V> do_GET(final K key) {
|
||||
try {
|
||||
final RBucket<CacheValueHolder<V>> rb = this.client.getBucket(getCacheKey(key));
|
||||
final CacheValueHolder<V> holder = rb.get();
|
||||
if (Objects.nonNull(holder)) {
|
||||
final long now = System.currentTimeMillis(), expire = holder.getExpireTime();
|
||||
if (expire > 0 && now >= expire) {
|
||||
return CacheGetResult.EXPIRED_WITHOUT_MSG;
|
||||
}
|
||||
return new CacheGetResult<>(CacheResultCode.SUCCESS, null, holder);
|
||||
}
|
||||
return CacheGetResult.NOT_EXISTS_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("GET", key, e);
|
||||
return new CacheGetResult<>(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
protected MultiGetResult<K, V> do_GET_ALL(final Set<? extends K> keys) {
|
||||
try {
|
||||
final Map<K, CacheGetResult<V>> retMap = new HashMap<>(1 << 4);
|
||||
if (Objects.nonNull(keys) && !keys.isEmpty()) {
|
||||
final Map<K, String> keyMap = new HashMap<>(keys.size());
|
||||
for (K k : keys) {
|
||||
if (Objects.nonNull(k)) {
|
||||
final String key = getCacheKey(k);
|
||||
if (Objects.nonNull(key)) {
|
||||
keyMap.put(k, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!keyMap.isEmpty()) {
|
||||
final Map<String, Object> kvMap = this.client.getBuckets().get(keyMap.values().toArray(new String[0]));
|
||||
final long now = System.currentTimeMillis();
|
||||
for (K k : keys) {
|
||||
final String key = keyMap.get(k);
|
||||
if (Objects.nonNull(key) && Objects.nonNull(kvMap)) {
|
||||
final CacheValueHolder<V> holder = (CacheValueHolder<V>) kvMap.get(key);
|
||||
if (Objects.nonNull(holder)) {
|
||||
final long expire = holder.getExpireTime();
|
||||
final CacheGetResult<V> ret = (expire > 0 && now >= expire) ? CacheGetResult.EXPIRED_WITHOUT_MSG :
|
||||
new CacheGetResult<>(CacheResultCode.SUCCESS, null, holder);
|
||||
retMap.put(k, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
retMap.put(k, CacheGetResult.NOT_EXISTS_WITHOUT_MSG);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new MultiGetResult<>(CacheResultCode.SUCCESS, null, retMap);
|
||||
} catch (Throwable e) {
|
||||
logError("GET_ALL", "keys(" + (Objects.nonNull(keys) ? keys.size() : 0) + ")", e);
|
||||
return new MultiGetResult<>(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheResult do_PUT(final K key, final V value, final long expireAfterWrite, final TimeUnit timeUnit) {
|
||||
try {
|
||||
final CacheValueHolder<V> holder = new CacheValueHolder<>(value, timeUnit.toMillis(expireAfterWrite));
|
||||
this.client.getBucket(getCacheKey(key)).set(holder, expireAfterWrite, timeUnit);
|
||||
return CacheGetResult.SUCCESS_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("PUT", key, e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheResult do_PUT_ALL(final Map<? extends K, ? extends V> map, final long expireAfterWrite, final TimeUnit timeUnit) {
|
||||
try {
|
||||
if (Objects.nonNull(map) && !map.isEmpty()) {
|
||||
final long expire = timeUnit.toMillis(expireAfterWrite);
|
||||
final RBatch batch = this.client.createBatch();
|
||||
map.forEach((k, v) -> {
|
||||
final CacheValueHolder<V> holder = new CacheValueHolder<>(v, expire);
|
||||
batch.getBucket(getCacheKey(k)).setAsync(holder, expireAfterWrite, timeUnit);
|
||||
});
|
||||
batch.execute();
|
||||
}
|
||||
return CacheResult.SUCCESS_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("PUT_ALL", "map(" + map.size() + ")", e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheResult do_REMOVE(final K key) {
|
||||
try {
|
||||
final boolean ret = this.client.getBucket(getCacheKey(key)).delete();
|
||||
return ret ? CacheResult.SUCCESS_WITHOUT_MSG : CacheResult.FAIL_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("REMOVE", key, e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheResult do_REMOVE_ALL(final Set<? extends K> keys) {
|
||||
try {
|
||||
if (Objects.nonNull(keys) && !keys.isEmpty()) {
|
||||
final RBatch batch = this.client.createBatch();
|
||||
keys.forEach(key -> batch.getBucket(getCacheKey(key)).deleteAsync());
|
||||
batch.execute();
|
||||
}
|
||||
return CacheResult.SUCCESS_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("REMOVE_ALL", "keys(" + keys.size() + ")", e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CacheResult do_PUT_IF_ABSENT(final K key, final V value, final long expireAfterWrite, final TimeUnit timeUnit) {
|
||||
try {
|
||||
final CacheValueHolder<V> holder = new CacheValueHolder<>(value, timeUnit.toMillis(expireAfterWrite));
|
||||
final boolean success = this.client.getBucket(getCacheKey(key)).trySet(holder, expireAfterWrite, timeUnit);
|
||||
return success ? CacheResult.SUCCESS_WITHOUT_MSG : CacheResult.EXISTS_WITHOUT_MSG;
|
||||
} catch (Throwable e) {
|
||||
logError("PUT_IF_ABSENT", key, e);
|
||||
return new CacheResult(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.redisson;
|
||||
|
||||
import com.alicp.jetcache.CacheManager;
|
||||
import com.alicp.jetcache.external.ExternalCacheBuilder;
|
||||
import com.alicp.jetcache.support.BroadcastManager;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
/**
|
||||
* Created on 2022/7/12.
|
||||
*
|
||||
* @author <a href="mailto:jeason1914@qq.com">yangyong</a>
|
||||
*/
|
||||
public class RedissonCacheBuilder<T extends ExternalCacheBuilder<T>> extends ExternalCacheBuilder<T> {
|
||||
|
||||
public static class RedissonDataCacheBuilderImpl extends RedissonCacheBuilder<RedissonDataCacheBuilderImpl> {
|
||||
|
||||
}
|
||||
|
||||
public static RedissonDataCacheBuilderImpl createBuilder() {
|
||||
return new RedissonDataCacheBuilderImpl();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"all"})
|
||||
protected RedissonCacheBuilder() {
|
||||
buildFunc(config -> new RedissonCache((RedissonCacheConfig) config));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"all"})
|
||||
public RedissonCacheConfig getConfig() {
|
||||
if (this.config == null) {
|
||||
this.config = new RedissonCacheConfig();
|
||||
}
|
||||
return (RedissonCacheConfig) this.config;
|
||||
}
|
||||
|
||||
public T redissonClient(final RedissonClient client) {
|
||||
this.getConfig().setRedissonClient(client);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportBroadcast() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BroadcastManager createBroadcastManager(final CacheManager cacheManager) {
|
||||
final RedissonCacheConfig<?, ?> c = (RedissonCacheConfig<?, ?>) this.getConfig().clone();
|
||||
return new RedissonBroadcastManager(cacheManager, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.lingniu.framework.plugin.jetcache.redisson;
|
||||
|
||||
import com.alicp.jetcache.external.ExternalCacheConfig;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
/**
|
||||
* Created on 2022/7/12.
|
||||
*
|
||||
* @author <a href="mailto:jeason1914@qq.com">yangyong</a>
|
||||
*/
|
||||
public class RedissonCacheConfig<K, V> extends ExternalCacheConfig<K, V> {
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
public RedissonClient getRedissonClient() {
|
||||
return redissonClient;
|
||||
}
|
||||
|
||||
public void setRedissonClient(final RedissonClient redissonClient) {
|
||||
this.redissonClient = redissonClient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.lingniu.framework.plugin.jetcache.autoconfigure.JetCacheAutoConfiguration
|
||||
@@ -0,0 +1,122 @@
|
||||
# 【重要】jetcache详细资料---参考官网
|
||||
|
||||
## 概述 (Overview)
|
||||
|
||||
1. 基于 JetCache 封装的企业级二级缓存解决方案,提供本地 JVM 本地缓存和远程 Redis 缓存的组合缓存能力
|
||||
2. 核心能力
|
||||
* 二级缓存机制:
|
||||
|
||||
- 一级缓存:本地 JVM 缓存(基于 Caffeine等)
|
||||
- 二级缓存:远程 Redis 缓存(redisson 模式)
|
||||
|
||||
* 多样化缓存配置:
|
||||
- 本地缓存:支持 Caffeine 类型,可配置缓存数量限制和过期时间
|
||||
- 远程缓存:支持 redisson 类型
|
||||
- 多实例支持:可配置多个缓存分组(如 default、employee 等)
|
||||
* 注解式缓存操作:
|
||||
- @Cached:标记方法结果需要缓存,支持缓存名称、过期时间等配置
|
||||
- @CacheRefresh:支持缓存自动刷新机制
|
||||
- @EnableMethodCache:启用 JetCache Bean 扫描
|
||||
* 灵活的缓存策略:
|
||||
- 支持不同的 Key 生成策略
|
||||
- 可配置缓存过期时间和时间单位
|
||||
- 支持不同的缓存类型(本地、远程、双向)
|
||||
|
||||
3. 适用场景:该组件特别适用于需要高性能缓存访问的企业级应用,通过本地+远程的二级缓存架构,在保证缓存访问速度的同时,确保缓存数据的共享和一致性。通过注解方式简化了缓存的使用。
|
||||
* 高并发读场景:需要减少数据库访问压力,提升系统响应速度的业务场景
|
||||
* 高可用访问:需要自动感知 Redis 集群变化以及故障自动切换能力的应用场景
|
||||
* 复杂查询结果缓存:对于计算复杂或关联查询较多的数据结果进行缓存
|
||||
* 数据一致性要求较高:需要通过二级缓存机制保证数据访问性能和一致性的场景
|
||||
* 需要缓存自动刷新:对于有一定时效性要求但不需要实时更新的数据
|
||||
|
||||
## 如何配置--更多参数参考:更多配置请参考官网jetcache
|
||||
|
||||
* 此处为了统一中间件配置前缀framework.lingniu.jetcache 和更好的个性化扩展, 其他jetcache所有配置方式未改变
|
||||
* 请先依赖:lingniu-framework-plugin-redisson
|
||||
redissonClient 就是 RedissonConfig配置的key名称
|
||||
|
||||
```yaml
|
||||
framework:
|
||||
lingniu:
|
||||
jetcache:
|
||||
# 需要隐藏的包路径(数组),默认为空
|
||||
hiddenPackages: [ ]
|
||||
# 统计信息输出间隔(分钟),默认为 0(不输出)
|
||||
statIntervalMinutes: 10
|
||||
# 是否在缓存名称中包含区域(area)信息,默认为 true
|
||||
areaInCacheName: true
|
||||
# 是否开启缓存穿透保护,默认为 false
|
||||
penetrationProtect: false
|
||||
# 本地缓存配置
|
||||
local:
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
ca2:
|
||||
# 本地缓存实现类类型,支持:linkedhashmap/caffeine
|
||||
type: linkedhashmap
|
||||
# 缓存key数量限制, 默认100
|
||||
limit: 100
|
||||
default:
|
||||
# 本地缓存实现类类型,支持:linkedhashmap/caffeine
|
||||
type: caffeine
|
||||
# 缓存key数量限制, 默认100
|
||||
limit: 100
|
||||
# 过期时间,0为不失效
|
||||
expireAfterAccessInMillis: 0
|
||||
# key 转换器,用于序列化,目前支持:NONE、FASTJSON、JACKSON、FASTJSON2
|
||||
keyConvertor: FASTJSON2
|
||||
remote:
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
ca2:
|
||||
# 远程缓存实现类类型,目前支持:redisson
|
||||
type: redisson
|
||||
# 远程缓存客户端名称,默认r1 -- todo 需要在application-redisson.yml中配置
|
||||
redissonClient: r1
|
||||
# key 前缀
|
||||
keyPrefix: "cacheKeyPrefix:"
|
||||
# 连接超时时间ms
|
||||
timeout: 2000
|
||||
# 重试次数
|
||||
maxAttempt: 5
|
||||
# 连接池配置
|
||||
poolConfig:
|
||||
maxTotal: 8
|
||||
maxIdle: 8
|
||||
minIdle: 0
|
||||
# key 转换器,用于序列化,目前支持:NONE、FASTJSON、JACKSON、FASTJSON2
|
||||
keyConvertor: FASTJSON2
|
||||
# JAVA, KRYO,KRYO5,自定义spring beanName
|
||||
valueEncoder: JAVA
|
||||
# JAVA, KRYO,KRYO5,自定义spring beanName
|
||||
valueDecoder: JAVA
|
||||
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
|
||||
default:
|
||||
# 远程缓存实现类类型,目前支持:redisson
|
||||
type: redisson
|
||||
# 远程缓存客户端名称,默认r1 -- todo 需要在application-redisson.yml中配置
|
||||
redissonClient: r1
|
||||
|
||||
```
|
||||
|
||||
## 如何使用-
|
||||
|
||||
```java
|
||||
//启动 扫描类添加注解
|
||||
@EnableMethodCache(basePackages = "cn.lingniu.*")
|
||||
@SpringBootApplication
|
||||
public class CacheApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CacheApplication.class, args);
|
||||
}
|
||||
}
|
||||
// 多种使用方式参考
|
||||
// 1. 注解方式
|
||||
@CachePenetrationProtect
|
||||
@Cached(name = "orderCache:", key = "#orderId", expire = 3600, cacheType = CacheType.BOTH)
|
||||
@CacheRefresh(refresh = 10, timeUnit = TimeUnit.MINUTES)
|
||||
public DataResult<KeyValueEntity> getOrderById(String orderId) {
|
||||
...
|
||||
}
|
||||
// 2. SimpleCacheManager方式
|
||||
Cache<Object, Object> localCache = simpleCacheManager.getOrCreateCache(QuickConfig.newBuilder(localArea, "user:").cacheType(CacheType.LOCAL).build());
|
||||
```
|
||||
|
||||
34
lingniu-framework-plugin/cache/lingniu-framework-plugin-redisson/pom.xml
vendored
Normal file
34
lingniu-framework-plugin/cache/lingniu-framework-plugin-redisson/pom.xml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-redisson</artifactId>
|
||||
<name>lingniu-framework-plugin-redisson</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.lingniu.framework.plugin.redisson;
|
||||
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class RedissonClientFactory {
|
||||
|
||||
private static volatile Map<String, RedissonClient> redisMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static void putRedissonClient(String beanName, RedissonClient redissonClient) {
|
||||
redisMap.put(beanName, redissonClient);
|
||||
}
|
||||
|
||||
public static RedissonClient getRedissonClient(String beanName) {
|
||||
if (ObjectEmptyUtils.isEmpty(beanName) || !redisMap.containsKey(beanName)) {
|
||||
throw new IllegalStateException("(redisson)bean-对应的RedissonClient未注册:" + beanName);
|
||||
}
|
||||
return redisMap.get(beanName);
|
||||
}
|
||||
|
||||
public static Map<String, RedissonClient> getRedisMap() {
|
||||
return redisMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.lingniu.framework.plugin.redisson;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 锁
|
||||
**/
|
||||
@SuppressWarnings("all")
|
||||
public interface RedissonClusterLockerService {
|
||||
|
||||
default public <T, R> R wrapLock(T source, Function<T, String> fun,
|
||||
Function<T, String> keyGetter, Function<T, R> wrapFun) {
|
||||
return wrapLock(source, fun, keyGetter, wrapFun, 15L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
<T, R> R wrapLock(T source, Function<T, String> fun,
|
||||
Function<T, String> keyGetter, Function<T, R> wrapFun,
|
||||
Long leaseTime, TimeUnit leaseTimeUnit);
|
||||
|
||||
default public <T, R> R wrapLock(T source, Function<T, String> keyGetter, Function<T, R> wrapFun) {
|
||||
return wrapLock(source, (t) -> {
|
||||
String key = keyGetter.apply(source);
|
||||
return delivery(key);
|
||||
}, keyGetter, wrapFun);
|
||||
}
|
||||
|
||||
String delivery(String key);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.lingniu.framework.plugin.redisson;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 支持注解获取锁
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface RedissonLockAction {
|
||||
|
||||
/**
|
||||
* RedissonConfig 中 remote 的 key 名字
|
||||
*/
|
||||
String redissonName();
|
||||
/**
|
||||
* 锁的资源,key。支持spring El表达式
|
||||
*/
|
||||
@AliasFor("key")
|
||||
String value() default "'default'";
|
||||
@AliasFor("value")
|
||||
String key() default "'default'";
|
||||
/**
|
||||
* 锁类型
|
||||
*/
|
||||
RedissonLockType lockType() default RedissonLockType.REENTRANT_LOCK;
|
||||
/**
|
||||
* 获取锁等待时间,默认3秒
|
||||
*/
|
||||
long waitTime() default 3000L;
|
||||
/**
|
||||
* 锁自动释放时间,默认10秒
|
||||
*/
|
||||
long leaseTime() default 10000L;
|
||||
/**
|
||||
* 时间单位
|
||||
*/
|
||||
TimeUnit unit() default TimeUnit.MILLISECONDS;
|
||||
/**
|
||||
* 锁失败是否Throw异常
|
||||
*/
|
||||
boolean throwException() default false;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.lingniu.framework.plugin.redisson;
|
||||
|
||||
/**
|
||||
* 锁类型
|
||||
*/
|
||||
public enum RedissonLockType {
|
||||
/**
|
||||
* 读锁
|
||||
*/
|
||||
READ_LOCK,
|
||||
/**
|
||||
* 写锁
|
||||
*/
|
||||
WRITE_LOCK,
|
||||
/**
|
||||
* 可重入锁
|
||||
*/
|
||||
REENTRANT_LOCK,
|
||||
/**
|
||||
* 公平锁
|
||||
*/
|
||||
FAIR_LOCK;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.lingniu.framework.plugin.redisson.builder;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedisHostAndPort;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonProperties;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.config.Config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public abstract class RedissonAbstractClientBuilder {
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private RedissonProperties redissonProperties;
|
||||
|
||||
protected RedissonAbstractClientBuilder(RedissonProperties redissonProperties) {
|
||||
this.redissonProperties = redissonProperties;
|
||||
}
|
||||
|
||||
protected abstract void config(Config redssionConfig, Set<RedisHostAndPort> redisHostAndPorts);
|
||||
|
||||
public Config build() {
|
||||
Config redissionConfig = new Config();
|
||||
Set<RedisHostAndPort> redisHostAndPorts = parseRedisHostAndPort(redissonProperties.getRedisAddresses());
|
||||
config(redissionConfig, redisHostAndPorts);
|
||||
return redissionConfig;
|
||||
}
|
||||
|
||||
public Set<RedisHostAndPort> parseRedisHostAndPort(String redisAddress) {
|
||||
Set<RedisHostAndPort> redisHostAndPorts = new HashSet<>();
|
||||
// 分离地址部分和密码部分
|
||||
String[] parts = redisAddress.split(";");
|
||||
String addressPart = parts[0];
|
||||
String password = parts.length > 1 ? parts[1] : null;
|
||||
// 解析host:port格式的地址
|
||||
String[] hosts = addressPart.split(",");
|
||||
for (String hostPort : hosts) {
|
||||
hostPort = hostPort.trim();
|
||||
if (hostPort.contains(":")) {
|
||||
int colonIndex = hostPort.indexOf(":");
|
||||
String host = hostPort.substring(0, colonIndex);
|
||||
int port = Integer.parseInt(hostPort.substring(colonIndex + 1));
|
||||
RedisHostAndPort redisHostAndPort = new RedisHostAndPort();
|
||||
redisHostAndPort.setHost(host);
|
||||
redisHostAndPort.setPort(port);
|
||||
if (password != null) {
|
||||
redisHostAndPort.setPkey(password);
|
||||
}
|
||||
redisHostAndPorts.add(redisHostAndPort);
|
||||
}
|
||||
}
|
||||
return redisHostAndPorts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.lingniu.framework.plugin.redisson.builder;
|
||||
|
||||
|
||||
import cn.lingniu.framework.plugin.core.context.ApplicationNameContext;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedisHostAndPort;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonProperties;
|
||||
import cn.lingniu.framework.plugin.util.ip.IpUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.config.ClusterServersConfig;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.config.ReadMode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @description: 集群类型
|
||||
**/
|
||||
public class RedissonClusterClientBuilder extends RedissonAbstractClientBuilder {
|
||||
|
||||
public RedissonClusterClientBuilder(RedissonProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void config(Config redssionConfig, Set<RedisHostAndPort> redisHostAndPorts) {
|
||||
ClusterServersConfig clusterServersConfig = redssionConfig.useClusterServers();
|
||||
if (StringUtils.isEmpty(getRedissonProperties().getClientName())) {
|
||||
clusterServersConfig.setClientName(ApplicationNameContext.getApplicationName() + ":" + IpUtil.getIp());
|
||||
}
|
||||
clusterServersConfig.setMasterConnectionMinimumIdleSize(getRedissonProperties().getConnectionMinimumIdleSize());
|
||||
clusterServersConfig.setSlaveConnectionMinimumIdleSize(getRedissonProperties().getConnectionMinimumIdleSize());
|
||||
clusterServersConfig.setMasterConnectionPoolSize(getRedissonProperties().getConnectionPoolSize());
|
||||
clusterServersConfig.setSlaveConnectionPoolSize(getRedissonProperties().getConnectionPoolSize());
|
||||
clusterServersConfig.setIdleConnectionTimeout(getRedissonProperties().getIdleConnectionTimeout());
|
||||
clusterServersConfig.setConnectTimeout(getRedissonProperties().getConnectTimeout());
|
||||
clusterServersConfig.setTimeout(getRedissonProperties().getTimeout());
|
||||
clusterServersConfig.setRetryAttempts(getRedissonProperties().getRetryAttempts());
|
||||
RedisHostAndPort redisHostAndPort = redisHostAndPorts.stream().findAny().get();
|
||||
clusterServersConfig.setPassword(redisHostAndPort.getPkey());
|
||||
clusterServersConfig.setCheckSlotsCoverage(getRedissonProperties().getCheckSlotsCoverage());
|
||||
clusterServersConfig.setReadMode(ReadMode.valueOf(getRedissonProperties().getReadMode()));
|
||||
redisHostAndPorts.stream().forEach(h -> {
|
||||
clusterServersConfig.addNodeAddress(String.format("redis://%s/", h.getHost() + ":" + h.getPort()));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.lingniu.framework.plugin.redisson.builder;
|
||||
|
||||
import cn.lingniu.framework.plugin.core.context.ApplicationNameContext;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedisHostAndPort;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonProperties;
|
||||
import cn.lingniu.framework.plugin.util.ip.IpUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.config.SingleServerConfig;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* @description: 单节点类型
|
||||
**/
|
||||
public class RedissonStandaloneClientBuilder extends RedissonAbstractClientBuilder {
|
||||
|
||||
|
||||
public RedissonStandaloneClientBuilder(RedissonProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void config(Config redssionConfig, Set<RedisHostAndPort> redisHostAndPorts) {
|
||||
SingleServerConfig singleServerConfig = redssionConfig.useSingleServer();
|
||||
if (StringUtils.isEmpty(getRedissonProperties().getClientName())) {
|
||||
singleServerConfig.setClientName(ApplicationNameContext.getApplicationName() + ":" + IpUtil.getIp());
|
||||
}
|
||||
singleServerConfig.setDatabase(getRedissonProperties().getDatabase());
|
||||
singleServerConfig.setConnectionMinimumIdleSize(getRedissonProperties().getConnectionMinimumIdleSize());
|
||||
singleServerConfig.setConnectionPoolSize(getRedissonProperties().getConnectionPoolSize());
|
||||
singleServerConfig.setIdleConnectionTimeout(getRedissonProperties().getIdleConnectionTimeout());
|
||||
singleServerConfig.setConnectTimeout(getRedissonProperties().getConnectTimeout());
|
||||
singleServerConfig.setTimeout(getRedissonProperties().getTimeout());
|
||||
singleServerConfig.setRetryAttempts(getRedissonProperties().getRetryAttempts());
|
||||
RedisHostAndPort redisHostAndPort = redisHostAndPorts.stream().findAny().get();
|
||||
singleServerConfig.setPassword(redisHostAndPort.getPkey());
|
||||
singleServerConfig.setAddress(String.format("redis://%s/", redisHostAndPort.getHost() + ":" + redisHostAndPort.getPort()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.lingniu.framework.plugin.redisson.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RedisHostAndPort {
|
||||
|
||||
private String host;
|
||||
|
||||
private int port;
|
||||
|
||||
private String pkey;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.lingniu.framework.plugin.redisson.config;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 集群类型
|
||||
**/
|
||||
public enum RedisType {
|
||||
STANDALONE("standalone", "单节点类型"),
|
||||
CLUSTER("cluster", "集群类型"),
|
||||
SENTINEL("sentinel", "哨兵类型");
|
||||
|
||||
@Getter
|
||||
private String type;
|
||||
|
||||
@Getter
|
||||
private String memo;
|
||||
|
||||
RedisType(String type, String memo) {
|
||||
this.type = type;
|
||||
this.memo = memo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.lingniu.framework.plugin.redisson.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* redisson 配置
|
||||
*/
|
||||
@ConfigurationProperties(prefix = RedissonConfig.PREFIX)
|
||||
@Data
|
||||
public class RedissonConfig {
|
||||
|
||||
public static final String PREFIX = "framework.lingniu.redisson";
|
||||
|
||||
|
||||
private Map<String, RedissonProperties> remote = new HashMap<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cn.lingniu.framework.plugin.redisson.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* 详细配置
|
||||
*/
|
||||
@Data
|
||||
public class RedissonProperties {
|
||||
|
||||
/**
|
||||
* redis连接串信息 host:port,host:port, 多个用,分割,最后一个是;是密码,可以不配置
|
||||
*/
|
||||
private String redisAddresses;
|
||||
|
||||
@Pattern(regexp = "^(SLAVE|MASTER|MASTER_SLAVE)$", message = "readMode must be one of SLAVE, MASTER, MASTER_SLAVE")
|
||||
private String readMode = "MASTER";
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private RedisType storageType = RedisType.CLUSTER;
|
||||
private String clientName = "";
|
||||
|
||||
@Min(value = 0, message = "database must be greater than or equal to 0")
|
||||
@Max(value = 15, message = "database must be less than or equal to 15")
|
||||
private int database = 0;
|
||||
|
||||
private int connectionMinimumIdleSize = 12;
|
||||
|
||||
private int connectionPoolSize = 32;
|
||||
|
||||
private int idleConnectionTimeout = 10000;
|
||||
|
||||
private int connectTimeout = 2000;
|
||||
|
||||
private int timeout = 2000;
|
||||
|
||||
private int retryAttempts = 4;
|
||||
//cluster: Slots检查
|
||||
private Boolean checkSlotsCoverage = true;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package cn.lingniu.framework.plugin.redisson.init;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClusterLockerService;
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClientFactory;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 初始化-RedissonClusterLockerService
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableConfigurationProperties({RedissonConfig.class})
|
||||
public class RedissonAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RedissonClusterLockerService redissonClusterLockerService() {
|
||||
return new RedissonClusterLockerService() {
|
||||
@Override
|
||||
public <T, R> R wrapLock(T source, Function<T, String> fun, Function<T, String> keyGetter, Function<T, R> wrapFun, Long leaseTime, TimeUnit leaseTimeUnit) {
|
||||
RedissonClient client = Optional.ofNullable(RedissonClientFactory.getRedissonClient(fun.apply(source))).orElseThrow(() -> new IllegalStateException("Redisson client not found for: " + fun.apply(source)));
|
||||
RLock lock = client.getLock(keyGetter.apply(source));
|
||||
try {
|
||||
lock.lock(leaseTime, leaseTimeUnit);
|
||||
return wrapFun.apply(source);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String delivery(String key) {
|
||||
return new ArrayList<>(RedissonClientFactory.getRedisMap().keySet()).toArray(new String[]{})[Math.abs(key.hashCode() % RedissonClientFactory.getRedisMap().size())];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
RedissonBeanRegisterPostProcessor redissonBeanRegister() {
|
||||
return new RedissonBeanRegisterPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package cn.lingniu.framework.plugin.redisson.init;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClientFactory;
|
||||
import cn.lingniu.framework.plugin.redisson.builder.RedissonClusterClientBuilder;
|
||||
import cn.lingniu.framework.plugin.redisson.builder.RedissonStandaloneClientBuilder;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedisType;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonConfig;
|
||||
import cn.lingniu.framework.plugin.redisson.config.RedissonProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@Slf4j
|
||||
public class RedissonBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
RedissonConfig config = Binder.get(applicationContext.getEnvironment()).bind(RedissonConfig.PREFIX, RedissonConfig.class).orElse(new RedissonConfig());
|
||||
Map<String, RedissonProperties> remote = config.getRemote();
|
||||
Optional.ofNullable(remote).ifPresent(b -> b.forEach((k, v) -> {
|
||||
if (applicationContext.containsBean(k)) {
|
||||
throw new IllegalStateException("redisson的实例对象已注册,请查看配置:" + k);
|
||||
}
|
||||
registerContainer(registry, k, v);
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerContainer(BeanDefinitionRegistry registry, String beanName, RedissonProperties redissonProperties) {
|
||||
Config redissonConfig = null;
|
||||
if (RedisType.STANDALONE.equals(redissonProperties.getStorageType())) {
|
||||
redissonConfig = new RedissonStandaloneClientBuilder(redissonProperties).build();
|
||||
} else if (RedisType.CLUSTER.equals(redissonProperties.getStorageType())) {
|
||||
redissonConfig = new RedissonClusterClientBuilder(redissonProperties).build();
|
||||
} else {
|
||||
throw new IllegalArgumentException("不支持的Redisson存储类型:" + redissonProperties.getStorageType());
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Redisson.class);
|
||||
builder.addConstructorArgValue(redissonConfig);
|
||||
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
|
||||
// 从ApplicationContext中获取已注册的Bean实例
|
||||
RedissonClient jedisCluster = applicationContext.getBean(beanName, RedissonClient.class);
|
||||
RedissonClientFactory.putRedissonClient(beanName, jedisCluster);
|
||||
if (!registry.containsBeanDefinition("redissonDistributedLockAspectConfiguration")) {
|
||||
registry.registerBeanDefinition("redissonDistributedLockAspectConfiguration",
|
||||
BeanDefinitionBuilder.rootBeanDefinition(RedissonDistributedLockAspectConfiguration.class).getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package cn.lingniu.framework.plugin.redisson.init;
|
||||
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonLockAction;
|
||||
import cn.lingniu.framework.plugin.redisson.RedissonClientFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Aspect 实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class RedissonDistributedLockAspectConfiguration {
|
||||
|
||||
private ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
@Pointcut("@annotation(cn.lingniu.framework.plugin.redisson.RedissonLockAction)")
|
||||
public void lockPoint() {
|
||||
}
|
||||
|
||||
@Around("lockPoint()")
|
||||
public Object around(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
|
||||
RedissonLockAction redissonLockAction = method.getAnnotation(RedissonLockAction.class);
|
||||
Object[] args = pjp.getArgs();
|
||||
String key = redissonLockAction.value();
|
||||
key = parse(key, method, args);
|
||||
|
||||
RLock lock = getLock(key, redissonLockAction);
|
||||
if (!lock.tryLock(redissonLockAction.waitTime(), redissonLockAction.leaseTime(), redissonLockAction.unit())) {
|
||||
log.warn("RedissonLockAction-获取锁失败: [{}]", key);
|
||||
if (redissonLockAction.throwException())
|
||||
throw new RuntimeException(String.format("RedissonLockAction-获取锁失败:[%s]", key));
|
||||
return null;
|
||||
}
|
||||
log.info("RedissonLockAction-获取锁成功: [{}]", key);
|
||||
try {
|
||||
return pjp.proceed();
|
||||
} catch (Exception e) {
|
||||
log.error(String.format("RedissonLockAction-方法锁执行异常:[%s]", key), e);
|
||||
throw e;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
log.info("RedissonLockAction-释放锁成功: [{}]", key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析spring EL表达式
|
||||
*/
|
||||
private String parse(String key, Method method, Object[] args) {
|
||||
String[] params = discoverer.getParameterNames(method);
|
||||
EvaluationContext context = new StandardEvaluationContext();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
context.setVariable(params[i], args[i]);
|
||||
}
|
||||
return parser.parseExpression(key).getValue(context, String.class);
|
||||
}
|
||||
|
||||
private RLock getLock(String key, RedissonLockAction redissonLockAction) {
|
||||
RedissonClient redissonClient = RedissonClientFactory.getRedissonClient(redissonLockAction.redissonName());
|
||||
switch (redissonLockAction.lockType()) {
|
||||
case REENTRANT_LOCK:
|
||||
return redissonClient.getLock(key);
|
||||
case FAIR_LOCK:
|
||||
return redissonClient.getFairLock(key);
|
||||
case READ_LOCK:
|
||||
return redissonClient.getReadWriteLock(key).readLock();
|
||||
case WRITE_LOCK:
|
||||
return redissonClient.getReadWriteLock(key).writeLock();
|
||||
default:
|
||||
throw new RuntimeException("RedissonLockAction-不支持的锁类型:" + redissonLockAction.lockType().name());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.lingniu.framework.plugin.redisson.init.RedissonAutoConfiguration
|
||||
@@ -0,0 +1,121 @@
|
||||
# 【重要】redisson详细资料-redis搭建---参考官网
|
||||
|
||||
## 概述 (Overview)
|
||||
|
||||
1. 基于 Redisson 封装的 Redis 集群操作和分布式锁组件,专门用于处理 Redis 集群环境下的分布式锁场景
|
||||
2. 核心能力
|
||||
* 高性能键值存储:基于RocksDB的高效读写能力,支持快速的数据存取操作。
|
||||
* 集群自适应感知:客户端能够感知集群变化并自动刷新配置
|
||||
* Redisson 操作:基于 Redisson 提供 Redis 集群操作能力
|
||||
* 分布式锁支持:支持多种类型的分布式锁:
|
||||
■ 可重入锁(REENTRANT_LOCK)
|
||||
■ 公平锁(FAIR_LOCK)
|
||||
■ 读锁(READ_LOCK)
|
||||
■ 写锁(WRITE_LOCK)
|
||||
* 注解式锁操作:通过 @LockAction 注解简化分布式锁的使用
|
||||
* 灵活配置:支持锁等待时间、自动释放时间、时间单位等参数配置
|
||||
* 异常处理:支持锁获取失败时的异常抛出或返回 null 两种处理方式
|
||||
* 支持多集群操作redis,也可扩展队列消费
|
||||
3. 适用场景:该组件特别适用于需要在 Redis 集群环境下使用分布式锁的企业级应用,通过注解方式简化了分布式锁的使用,提供了多种锁类型以满足不同业务场景的需求
|
||||
* 分布式系统:需要在分布式环境下保证数据一致性的场景
|
||||
* 高并发业务:需要防止并发操作导致数据不一致的业务场景
|
||||
* 集群环境:基于 Redis 集群部署的应用系统
|
||||
* 资源竞争控制:需要对共享资源进行并发访问控制的场景
|
||||
* 定时任务:分布式环境下需要确保任务单实例执行的定时任务
|
||||
* 库存扣减:电商系统中需要防止超卖的库存扣减场景
|
||||
* 幂等性保证:需要保证接口幂等性的业务操作。
|
||||
|
||||
## 如何配置--更多参数参考:RedissonConfig/RedissonProperties
|
||||
|
||||
```yaml
|
||||
framework:
|
||||
lingniu:
|
||||
redisson:
|
||||
remote:
|
||||
r1:
|
||||
# 应用id需在cachecloud申请
|
||||
redisAddresses: xxxx:6387
|
||||
# 客户端名称,默认为应用名 + IP
|
||||
clientName: ""
|
||||
# 单节点 Redis 默认数据库,默认为 0
|
||||
database: 0
|
||||
# 连接池最小空闲连接数,默认为 12
|
||||
connectionMinimumIdleSize: 12
|
||||
# 连接池最大连接数,默认为 32
|
||||
connectionPoolSize: 32
|
||||
# 空闲连接超时时间(毫秒),默认为 10000
|
||||
idleConnectionTimeout: 10000
|
||||
# 连接超时时间(毫秒),默认为 2000
|
||||
connectTimeout: 2000
|
||||
# 操作超时时间(毫秒),默认为 2000
|
||||
timeout: 2000
|
||||
# 操作重试次数,默认为 4
|
||||
retryAttempts: 4
|
||||
# 集群模式下是否检查 Slots 覆盖,默认为 true
|
||||
checkSlotsCoverage: true
|
||||
# 读取模式,默认为 "SLAVE"
|
||||
# 可选值:
|
||||
# - SLAVE: 从节点读取
|
||||
# - MASTER: 主节点读取
|
||||
# - MASTER_SLAVE: 主从节点读取
|
||||
readMode: "SLAVE"
|
||||
# 存储类型,默认为 "CLUSTER"
|
||||
# 可选值:
|
||||
# - CLUSTER: 集群模式
|
||||
# - SINGLE: 单节点模式
|
||||
# - SENTINEL: 哨兵模式
|
||||
# - REPLICATED: 复制模式
|
||||
storageType: "CLUSTER"
|
||||
# 实例名称
|
||||
r2:
|
||||
# 应用id需在cachecloud申请
|
||||
redisAddresses: xxx:6387
|
||||
# 单节点 Redis 默认数据库,默认为 0
|
||||
database: 0
|
||||
|
||||
```
|
||||
|
||||
## 如何使用--正常操作redis
|
||||
|
||||
```java
|
||||
@Autowired
|
||||
private RedissonClient test;
|
||||
// 或者
|
||||
RedissonFactory.getRedissonClient("test").api
|
||||
```
|
||||
|
||||
## 如何使用--分布式锁
|
||||
|
||||
```java
|
||||
/**
|
||||
* 使用 #orderId 参数作为锁的key
|
||||
*/
|
||||
@PostMapping("/process/{orderId}")
|
||||
@LockAction(
|
||||
redissonName = "r1",
|
||||
key = "#orderId",
|
||||
lockType = LockType.REENTRANT_LOCK,
|
||||
waitTime = 3000L, leaseTime = 30000L, unit = TimeUnit.MILLISECONDS,
|
||||
throwEx = true
|
||||
)
|
||||
public ResponseEntity<String> processOrder(@PathVariable String orderId) {
|
||||
// 业务逻辑
|
||||
return ResponseEntity.ok("Order processed: " + orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用请求参数
|
||||
*/
|
||||
@GetMapping("/query")
|
||||
@LockAction(
|
||||
redissonName = "defaultRedisson",
|
||||
key = "'query:' + #userId + ':' + #status",
|
||||
throwEx = true
|
||||
)
|
||||
public ResponseEntity<List<Order>> queryOrders(
|
||||
@RequestParam String userId,
|
||||
@RequestParam String status) {
|
||||
// 业务逻辑
|
||||
return ResponseEntity.ok(new ArrayList<>());
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-apollo</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.lingniu.framework.plugin.apollo.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = ApolloConfig.PRE_FIX)
|
||||
public class ApolloConfig {
|
||||
|
||||
public final static String PRE_FIX = "framework.lingniu.apollo";
|
||||
|
||||
/**
|
||||
* 是否开始Apollo配置
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* Meta地址
|
||||
*/
|
||||
@NotBlank
|
||||
private String meta;
|
||||
/**
|
||||
* 配置文件列表 以,分割
|
||||
*/
|
||||
private String namespaces = "";
|
||||
/**
|
||||
* 无需配置 app.id 等于 spring.application.name
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import com.ctrip.framework.apollo.Config;
|
||||
import com.ctrip.framework.apollo.ConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.ConfigService;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloProcessor;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Apollo Annotation Processor for Spring Application
|
||||
*
|
||||
* @author Jason Song(song_s@ctrip.com)
|
||||
*/
|
||||
public class ApolloAnnotationProcessor extends ApolloProcessor {
|
||||
|
||||
@Override
|
||||
protected void processField(Object bean, String beanName, Field field) {
|
||||
ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
|
||||
"Invalid type: %s for field: %s, should be Config", field.getType(), field);
|
||||
|
||||
String namespace = System.getProperty("apollo.bootstrap.namespaces", annotation.value());
|
||||
Config config = ConfigService.getConfig(namespace);
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processMethod(final Object bean, String beanName, final Method method) {
|
||||
ApolloConfigChangeListener annotation = AnnotationUtils
|
||||
.findAnnotation(method, ApolloConfigChangeListener.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Preconditions.checkArgument(parameterTypes.length == 1,
|
||||
"Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length,
|
||||
method);
|
||||
Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]),
|
||||
"Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0],
|
||||
method);
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
|
||||
String namespaceProperties = System.getProperty("apollo.bootstrap.namespaces", String.join(",", annotation.value()));
|
||||
String[] namespaces = namespaceProperties.split(",");
|
||||
String[] annotatedInterestedKeys = annotation.interestedKeys();
|
||||
String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
|
||||
ConfigChangeListener configChangeListener = changeEvent -> ReflectionUtils.invokeMethod(method, bean, changeEvent);
|
||||
|
||||
Set<String> interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
|
||||
Set<String> interestedKeyPrefixes = annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null;
|
||||
|
||||
for (String namespace : namespaces) {
|
||||
Config config = ConfigService.getConfig(namespace);
|
||||
|
||||
if (interestedKeys == null && interestedKeyPrefixes == null) {
|
||||
config.addChangeListener(configChangeListener);
|
||||
} else {
|
||||
config.addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import com.ctrip.framework.apollo.model.ConfigChange;
|
||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.cloud.context.scope.refresh.RefreshScope;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ApolloConfigChangeLogListener implements ApplicationContextAware {
|
||||
|
||||
@Resource
|
||||
RefreshScope refreshScope;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@ApolloConfigChangeListener
|
||||
public void onChange(ConfigChangeEvent changeEvent) {
|
||||
if (log.isInfoEnabled()) {
|
||||
for (String changedKey : changeEvent.changedKeys()) {
|
||||
ConfigChange changeInfo = changeEvent.getChange(changedKey);
|
||||
if (ObjectEmptyUtils.isEmpty(changeInfo)) {
|
||||
continue;
|
||||
}
|
||||
log.info("【apollo 配置变更】 - namespace: {}, property: {}, oldValue: {}, newValue: {}, changeType: {}",
|
||||
changeInfo.getNamespace(), changeInfo.getPropertyName(),
|
||||
changeInfo.getOldValue(), changeInfo.getNewValue(), changeInfo.getChangeType());
|
||||
}
|
||||
}
|
||||
applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
|
||||
refreshProperties(changeEvent);
|
||||
}
|
||||
|
||||
public void refreshProperties(ConfigChangeEvent changeEvent) {
|
||||
try {
|
||||
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
|
||||
if (ObjectEmptyUtils.isNotEmpty(refreshScope)) {
|
||||
refreshScope.refreshAll();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to refresh properties after Apollo config change", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.LoaderClassPath;
|
||||
|
||||
|
||||
public class ClassPoolUtils {
|
||||
|
||||
private static volatile ClassPool instance;
|
||||
|
||||
private ClassPoolUtils() {
|
||||
}
|
||||
|
||||
public static ClassPool getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ClassPoolUtils.class) {
|
||||
if (instance == null) {
|
||||
instance = ClassPool.getDefault();
|
||||
instance.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.lingniu.framework.plugin.apollo.extend;
|
||||
|
||||
import com.ctrip.framework.apollo.core.spi.Ordered;
|
||||
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValueProcessor;
|
||||
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
|
||||
import com.ctrip.framework.apollo.spring.annotation.SpringValueProcessor;
|
||||
import com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor;
|
||||
import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
|
||||
import com.ctrip.framework.apollo.spring.util.BeanRegistrationUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FrameworkApolloConfigRegistrarHelper implements com.ctrip.framework.apollo.spring.spi.ApolloConfigRegistrarHelper, Ordered {
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableApolloConfig.class.getName()));
|
||||
String[] namespaces = System.getProperty("apollo.bootstrap.namespaces", "application").split(",");
|
||||
//attributes.getStringArray("value");
|
||||
int order = attributes.getNumber("order");
|
||||
PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
|
||||
|
||||
Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
|
||||
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
|
||||
propertySourcesPlaceholderPropertyValues.put("order", 0);
|
||||
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
|
||||
PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
|
||||
PropertySourcesProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
|
||||
ApolloAnnotationProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(),
|
||||
SpringValueProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(),
|
||||
SpringValueDefinitionProcessor.class);
|
||||
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
|
||||
ApolloJsonValueProcessor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lingniu.framework.plugin.apollo.init;
|
||||
|
||||
import cn.lingniu.framework.plugin.apollo.extend.ApolloConfigChangeLogListener;
|
||||
import cn.lingniu.framework.plugin.apollo.config.ApolloConfig;
|
||||
import cn.lingniu.framework.plugin.util.config.PropertyUtils;
|
||||
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableApolloConfig
|
||||
@ConditionalOnProperty(prefix = ApolloConfig.PRE_FIX, name = "enabled", havingValue = "true")
|
||||
@Import({ApolloConfigChangeLogListener.class})
|
||||
public class ApolloAutoConfiguration implements InitializingBean {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
log.info("Apollo configuration enabled(启动), meta URL: {}", PropertyUtils.getProperty("apollo.meta"));
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user