官方也提供了spring boot jdbc 的demo,但是文档不是很清晰,在基础上做了修改,方便学习
环境准备
- docker-compose 文件
主要是mysql 数据库的准备, 当然testcontainer也是一个很不错的选择(测试环境使用)
version: "3"
services:
mysql:
image: mysql:5.7.16
ports:
- 3306:3306
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: dalongrong
MYSQL_DATABASE: ff4j_v1
TZ: Asia/Shanghai
代码使用
- 简单说明
默认官方的需要包含数据,但是为了测试的方便,提供了autocreate 以及createSchema,对于schema 也可以自己通过sql 导入 - 项目结构
├── docker-compose.yaml
├── pom.xml
└── src
└── main
├── java
│ └── org
│ └── ff4j
│ └── sample
│ ├── Application.java
│ ├── config
│ │ └── FF4JConfiguration.java
│ └── resources
│ └── SampleResource.java
└── resources
└── application.properties
- pom.xml
注意版本,默认的shapshot版本好像没有发布?,所以使用了release 版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-sample-springboot-jdbc</artifactId>
<packaging>jar</packaging>
?
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
?
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<ff4j.version>1.8.4</ff4j.version>
</properties>
?
<dependencies>
?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
?
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-spring-boot-starter</artifactId>
<version>${ff4j.version}</version>
</dependency>
?
<dependency>
<groupId>org.ff4j</groupId>
<artifactId>ff4j-store-springjdbc</artifactId>
<version>${ff4j.version}</version>
</dependency>
?
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
?
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
?
</dependencies>
?
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
?
</project>
- application 配置
主要是关于datasource的配置
spring.datasource.name=ff4j_db
spring.datasource.url=jdbc:mysql://localhost:3306/ff4j_v1
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=dalongrong
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- Application.java
package org.ff4j.sample;
?
import org.ff4j.FF4j;
import org.ff4j.core.Feature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
?
import javax.annotation.Resource;
?
@SpringBootApplication
public class Application implements CommandLineRunner {
?
@Autowired
FF4j getFF4j;
?
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
?
// 使用CommandLineRunner 接口,注册一个feature
@Override
public void run(String
Feature feature = getFF4j.getFeature("feature_X");
if(feature==null){
getFF4j.enable("feature_X");
}
}
}
- ff4j bean 注册
FF4JConfiguration.java
注意开启了审计日志以及自动创建schema以及feature
package org.ff4j.sample.config;
?
import javax.sql.DataSource;
?
import org.ff4j.FF4j;
import org.ff4j.springjdbc.store.EventRepositorySpringJdbc;
import org.ff4j.springjdbc.store.FeatureStoreSpringJdbc;
import org.ff4j.springjdbc.store.PropertyStoreSpringJdbc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
?
@Configuration()
?
public class FF4JConfiguration {
?
@Autowired
private DataSource dataSource;
?
@Bean
public FF4j getFF4j() {
FF4j ff4j = new FF4j();
ff4j.setFeatureStore(new FeatureStoreSpringJdbc(dataSource));
ff4j.setPropertiesStore(new PropertyStoreSpringJdbc(dataSource));
ff4j.setEventRepository(new EventRepositorySpringJdbc(dataSource));
ff4j.audit(true);
ff4j.createSchema();
ff4j.autoCreate(true);
return ff4j;
}
}
?
- rest api 创建
引用ff4j bean 以及获取feature
package org.ff4j.sample.resources;
?
import org.ff4j.FF4j;
import org.ff4j.spring.autowire.FF4JFeature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
?
@RestController
public class SampleResource {
@Autowired
private FF4j getFF4j;
?
@RequestMapping(value = "/", method = RequestMethod.GET, produces = "text/html")
public String sayHello() {
StringBuilder response = new StringBuilder("<html><body><ul>");
?
response.append("<p>Is <span style=\"color:red\">Awesome</span> feature activated ? from ff4j.check(\"feature_X\") <span style=\"color:blue\">");
response.append(getFF4j.check("feature_X"));
?
response.append("</span></body></html>");
return response.toString();
}
?
}
启动&&效果
- 启动数据库
docker-compose up -d
- 启动服务
mvn spring-boot:run
- 效果
db
访问
修改数据(直接从db,合理的方式是通过业务管理或者webconsole)
说明
以上是一个关于db的简单试用,实际使用还需要考虑各种性能问题以及安全问题,实际上如果查看ff4j bean 的创建,就会发现我们的
feature,event,以及properties 理论上都是可以分离的,同时也可以支持多种数据存储
- 附一个jdbc 的sql schema
-- Main Table to store Features
CREATE TABLE FF4J_FEATURES (
FEAT_UID VARCHAR(100),
ENABLE INTEGER NOT NULL,
DESCRIPTION VARCHAR(1000),
STRATEGY VARCHAR(1000),
EXPRESSION VARCHAR(255),
GROUPNAME VARCHAR(100),
PRIMARY KEY(FEAT_UID)
);
?
-- Roles to store ACL, FK to main table
CREATE TABLE FF4J_ROLES (
FEAT_UID VARCHAR(100) REFERENCES FF4J_FEATURES(FEAT_UID),
ROLE_NAME VARCHAR(100),
PRIMARY KEY(FEAT_UID, ROLE_NAME)
);
?
-- Feature Internal Custom Properties
CREATE TABLE FF4J_CUSTOM_PROPERTIES (
PROPERTY_ID VARCHAR(100) NOT NULL,
CLAZZ VARCHAR(255) NOT NULL,
CURRENTVALUE VARCHAR(255),
FIXEDVALUES VARCHAR(1000),
DESCRIPTION VARCHAR(1000),
FEAT_UID VARCHAR(100) REFERENCES FF4J_FEATURES(FEAT_UID),
PRIMARY KEY(PROPERTY_ID, FEAT_UID)
);
?
-- @PropertyStore (edit general properties)
CREATE TABLE FF4J_PROPERTIES (
PROPERTY_ID VARCHAR(100) NOT NULL,
CLAZZ VARCHAR(255) NOT NULL,
CURRENTVALUE VARCHAR(255),
FIXEDVALUES VARCHAR(1000),
DESCRIPTION VARCHAR(1000),
PRIMARY KEY(PROPERTY_ID)
);
?
-- @see JdbcEventRepository (audit event)
CREATE TABLE FF4J_AUDIT (
EVT_UUID VARCHAR(40) NOT NULL,
EVT_TIME TIMESTAMP NOT NULL,
EVT_TYPE VARCHAR(30) NOT NULL,
EVT_NAME VARCHAR(30) NOT NULL,
EVT_ACTION VARCHAR(30) NOT NULL,
EVT_HOSTNAME VARCHAR(100) NOT NULL,
EVT_SOURCE VARCHAR(30) NOT NULL,
EVT_DURATION INTEGER,
EVT_USER VARCHAR(30),
EVT_VALUE VARCHAR(100),
EVT_KEYS VARCHAR(255),
PRIMARY KEY(EVT_UUID, EVT_TIME)
);
参考资料
https://github.com/ff4j/ff4j/wiki/Store-Technologies#springjdbc