Initial commit

This commit is contained in:
Eric
2026-01-16 18:51:16 +08:00
commit 98c057de11
280 changed files with 16665 additions and 0 deletions

45
.gitignore vendored Normal file
View 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
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

15
.idea/checkstyle-idea.xml generated Normal file
View 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>

0
README.md Normal file
View File

View 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>

View File

@@ -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);
}
}

View File

@@ -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()
);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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> {
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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";
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}

View File

@@ -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");
}
}

View File

@@ -0,0 +1,9 @@
package cn.lingniu.demo.microservice;
import lombok.Data;
@Data
public class Contributor {
String login;
int contributions;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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");
}
}

View File

@@ -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; }
}
}

View File

@@ -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");
}
}

View File

@@ -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";
}
}

View File

@@ -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);
}
}

View File

@@ -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> {
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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 KRYOKRYO5自定义spring beanName
valueEncoder: JAVA
# JAVA KRYOKRYO5自定义spring beanName
valueDecoder: JAVA
# cache area 配置, 使用CacheManager或@Cache注解时 默认area为default
default:
# 远程缓存实现类类型目前支持redisson
type: redisson
# 远程缓存客户端名称默认r1 -- todo 需要在application-redisson.yml中配置
redissonClient: r1

View File

@@ -0,0 +1,6 @@
framework:
lingniu:
prometheus:
enabled: true
port: 30290
allowAssignPort: false

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,12 @@
framework:
lingniu:
web:
apiLog:
#开关
enable: true
apiEncrypt:
#开关
enable: false
algorithm: "AES"
requestKey: "xxx"
responseKey: "xxx"

View File

@@ -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

View File

@@ -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

View File

@@ -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: "对象示例"

View File

@@ -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>

View 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>

View File

@@ -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);
}
}

View File

@@ -0,0 +1,11 @@
package cn.lingniu.demo.web;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Contributor {
String login;
int contributions;
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,9 @@
framework:
lingniu:
web:
apiLog:
#开关
enable: true
spring:
cloud:
isOkHttp: false

View File

@@ -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 #注册中心密码

View File

@@ -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
View 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对业务进行异步处理;
* 等等
## 组件介绍
![img.png](img.png)

BIN
img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View 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>

View 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>

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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());
}
}

View File

@@ -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))));
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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")));
}
}

View File

@@ -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;
}
}

View File

@@ -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");
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.lingniu.framework.plugin.jetcache.autoconfigure.JetCacheAutoConfiguration

View File

@@ -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 KRYOKRYO5自定义spring beanName
valueEncoder: JAVA
# JAVA KRYOKRYO5自定义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());
```

View 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>

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -0,0 +1,23 @@
package cn.lingniu.framework.plugin.redisson;
/**
* 锁类型
*/
public enum RedissonLockType {
/**
* 读锁
*/
READ_LOCK,
/**
* 写锁
*/
WRITE_LOCK,
/**
* 可重入锁
*/
REENTRANT_LOCK,
/**
* 公平锁
*/
FAIR_LOCK;
}

View File

@@ -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;
}
}

View File

@@ -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()));
});
}
}

View File

@@ -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()));
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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<>();
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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 {
}
}

View File

@@ -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());
}
}
}

View File

@@ -0,0 +1,3 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.lingniu.framework.plugin.redisson.init.RedissonAutoConfiguration

View File

@@ -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<>());
}
```

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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