Camel 是一套定制的SpringBoot开发框架(Java),对提高开发效率,稳定程序质量,起到举足轻重的作用,确实是居家旅行必备之良药,特别是创业小公司,
能看到本框架,算你有福气。那就看下客户评价吧,虽然有一定的吹水成份,但能经历五年的洗礼与历史的选择,并在公司被广泛使用(350+项目使用),
有值得参考的点。补充:从公司出来后,更有新的认识与理解,对框架进行了重新构架与编码,希望你会喜欢!
=
新入职的同学如是说:“工作了这么多间公司,就你这套框架,叫我服,够实用够简单!”
走出去的同学如是说:“出去就拿老大这套框架代码,横着行,如果可以,值1个亿吧!”
四年竞争对手与亲密合作伙伴马爷:“用上就再也离不开,轻重都是刚刚好,公司就你(框架)最靠谱!”
=
代码仍在测试中,敬请期待...
序言
干就对啦,说不定框架能用上几年! —- Youcai 2016-06-01
仅以此文档献给2018年在普通岗位上努力工作的您。 —- Youcai 2019-01-26
Camel框架的零配置技术至少领先世界5-10年! —- Youcai 2022-02-18
升级SpingBoot2.5,历史交给我们的技术优化任务! —- Youcai 2022-04-20
重写并开源Camel框架,是企业向社会输出人才的必然产出!—- Youcai 2022-08-10
开始使用
Camel框架基于SpringBoot2.5.9打造(https://spring.io/projects/spring-boot/#support ),核心解决三件事:
- 开发环境复杂配置与启动问题,如开发环境,测试环境,生产环境等各种复杂的配置文件与启动等;
- 多数据源零配置优美解决方案,多数据源适配不再是难题,世界最优美的解决方案之一(领先世界五到十年);
- 参数最佳组合与调优,经历了千万级别甚至亿级别流量洗礼的项目参数组合与调优等;
学习框架最快的方法是把代码跑起来,那我们就先用起来吧,跟着一步一步来,可参考GIT提供的example:
首先引入SpringBoot 2.5.9:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.9</version>
</parent>
再引入Camel框架(看GIT分支的release记录):
<dependency>
<groupId>cc.goodrain.framework</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.5.9.32-RELEASE</version>
</dependency>
到此为止,你就可以开始使用Camel的所有功能了。
温馨提示(如对包管理比较熟,忽略下面这几段提示):
-
本框架已引入的类库,你的项目不再需要重复引入,已重复引入的,建议删除,怕版本不一致(可用IDE查看最终的JAR版本,看有没有多版本同时引入):
commons-lang3 spring-boot-starter-web spring-boot-starter-undertow spring-boot-starter-jdbc spring-boot-starter-data-redis mysql-connector-java tomcat-jdbc HikariCP jedis jackson-core jackson-databind kafka-clients elasticsearch-rest-high-level-client elasticsearch elasticsearch-rest-client
-
Springboot预定义的类库(见spring-boot-dependencies-2.5.9.pom),引用这些类库时,最好使用默认版本,如引入Springboot预定义的Gson类库时,像下面这样这样,不用定义
<version>
属性:<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency>
-
如果要重载Springboot预定义的类库,请在项目的根pom.xml里定义相应的版本属性,不要单独在
节点里定义,如使用elasticsearch,版本6与7是差异很大的,那么选择不同的elasticsearch版本时,要在根pom. xml里定义并重载全局统一版本号(跟SpringBoot预定的名字要一致哈),否则可能会出错,如: <properties> <elasticsearch.version>6.2.2</elasticsearch.version> </properties>
1.1、camel-boot(开发环境复杂配置与启动问题->解决方案)
camel-boot继承了spring-boot几乎所有优点,同时约定并稳定了一些组件的参数与并提供优化方案,非常适合追求高开发效率与质量的优秀程序员(特别是优秀的你)。
main入口程序如下,请使用CamelSpringApplication启动类来代替SpringBoot默认的启动类,样本如下:
@SpringBootApplication(scanBasePackages = {"cc.goodrain.demo"})
@ConfigurationProperties(prefix = "cc.goodrain.demo")
@CamelBootModule("example")
@CamelBootWebEnvironment(CamelBootWebEnvironment.CamelBootWebEnvironmentType.Yes) //这个可以不写,默认是Yes
@EnableSwagger2
public class ApplicationMain {
public static void main(String[] args) {
new CamelSpringApplication(ApplicationMain.class).run(args);
}
}
运行上面ApplicationMain
类,会输出相关帮助信息(部分摘要如下):
欢迎使用Camel框架,启动配置文件如下:
配置文件表达式:application(-部署环境)(-项目模块)?(-机房标识)?.properties
部署环境:值仅能是local|dev|test|stage|prod之一,值从环境变量中DWENV读取,不配置默认是local
项目模块(选配):使用注解类@CamelBootModule(x)标记@SpringBootApplication的启动类
机房标识(选配):使用JVM参数来-Dserver.region=x来标记(现在几乎没有人用这个项)
::
>>>当前启动配置文件是:application.properties
>>>当前启动配置文件是:application-local.properties
>>>当前启动配置文件是:application-local-web.properties
>>>程序按顺序处理上面的配置文件,相同的配置项,后面的会覆盖前面的(last-wins strategy)!!!
下面对上面的参数进行一些补充说明:
-
开发环境,模块,多区部署参数配置说明如下;
开发环境参数设置:-DDWENV=local|dev|test|stage|prod(JVM启动参数里设置) 开发模块参数设置:@CamelBootModule("x") (非必选,主要是方便同一个项目多个模块定位配置文件) 部署区域参数设置:-Dserver.region=x (非必选,主要是方便程序全球化部署)
-
多级配置文件继承与重载读取顺序与优先级(last-wins strategy);
application.properties application-部署环境.properties (如有) application-部署环境-项目模块.properties (如有)
-
web与非web环境参数配置;
@CamelBootWebEnvironment(CamelBootWebEnvironment.CamelBootWebEnvironmentType.Yes) 会启动WEB服务器 @CamelBootWebEnvironment(CamelBootWebEnvironment.CamelBootWebEnvironmentType.NO) 不会启动WEB服务器
-
其它参数约定;
实际项目使用测试发现Undertow性能更好,特别是占用内存较小,而且高并发时close_wait的TCP问题更少, 本框架由默认Tomcat服务器改成了Undertow服务器。
1.2、 camel-data(多数据源零配置优美解决方案)
在说明怎样使用camel-data
前,先了解一下最新版本springboot
怎样零配置的。
先看一下Mysql程序的原生工作流程吧:首先配置数据源的文件(帐号、密码、数据库信息等),接着编写DataSourceProperties的程序,接着编写数据源如DataSource程序,再接着编写JdbcTemplate 的程序,至少要做4步流程,具体见:https://docs.spring.io/spring-boot/docs/2.5.9/reference/html/howto.html#howto.data-access.configure-two-datasources。
以我们项目为例,大概有20个mysql数据源,原生程序就要写超过20*4=80份程序,我相信对于开发与维护都是非常艰巨的任务。而camel-data做的事情就是一步到位给你生成相关的程序(这里又叫Bean),直接使用,让我们更多精力关注业务,提高生产效率。
根据个人开发经验,camel框架集成了使用最多的Mysql、Redis、Kafka、Elasticsearch共四个数据源。其它数据源可按官方配置或自己实现。最后,使用本框架后,仍然可以使用默认的数据源配置方式。
1.2.1、 Mysql 使用说明
先配置mysql的数据库配置文件,样本如下:
camel.mysql.main.url=127.0.0.1:3306:dbname
camel.mysql.main.username=Youcai
camel.mysql.main.password=Youcai_like_demo
camel.mysql.main.initialSize=30
camel.mysql.main.minIdle=30
camel.mysql.main.maxIdle=50
camel.mysql.main.maxActive=50
camel.mysql.main.maxAge=28800000
camel.mysql.main.testOnBorrow=true
camel.mysql.main.testWhileIdle=true
#这里的validationQuery建议使用我这样子,对云厂商Failover数据库切换有奇效
camel.mysql.main.validationQuery=select case when @@read_only + @@innodb_read_only = 0 then 1 else (select table_name from information_schema.tables limit 2) end as `1`
camel.mysql.main.validationInterval=30000
注意上面配置的关键字是main
,框架将按这个关键字生成如下Bean,可根据实际情况选择注入即可马上使用,
建议注入mainCamelJdbcTemplate
或mainNamedParameterJdbcTemplate
使用。
mainMysqlDataSource, mainJdbcTemplate, mainCamelJdbcTemplate, mainNamedParameterJdbcTemplate
下面是使用程序样本:
@Repository
public class PeopleDaoImpl implements PeopleDao {
@Autowired
@Qualifier("mainCamelJdbcTemplate")
CamelJdbcTemplate mainCamelJdbcTemplate;
@Override
public People getPeopleById(Long id) {
String sql = "select * from people where id = ?";
return mainCamelJdbcTemplate.iQueryBean(sql, People.class, id);
}
}
高级话题:
-
url参数支持二种方式。标准方式与非标准方式。
标准方式,像下面的简要配置:数据库连接:端口:数据库名,然后camel框架会生成标准的连接字符串,简化配置: camel.mysql.main.url=127.0.0.1:3306:dbname 非标准方式,如果想自己定制更灵活的url连接, 请根据mysql驱动程序的标准配置(https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html ),如: camel.mysql.main.url=jdbc:mysql://127.0.0.1:3306/x?useUnicode=true&characterEncoding=utf-8
-
支持哪些数据源?本框架默认是Tomcat数据源,要换数据源,请设置dataSourceType参数,建议一个项目固定一类数据源,方便维护,设置成Hikari数据源配置如下:
camel.mysql.main.dataSourceType=com.zaxxer.hikari.HikariDataSource 支持哪些参数?上面样本默认参数的是Tomcat数据源配置, Tomcat支持的配置参数请看:`org.apache.tomcat.jdbc.pool.PoolConfiguration`, Hikari支持的配置参数请参看类`com.zaxxer.hikari.HikariConfig`(Hikari的字段与Set方法不完全对应,要以set方法的名字为准) 如Hikari里的方法`public void setMaximumPoolSize(int maxPoolSize)`,设置时使用`maximumPoolSize`
-
支持事务Bean吗?支持但默认不开启,如果需要请配置
transaction
属性,如:camel.mysql.main.transaction=true 则再生成如下Bean: mainMysqlTransactionManager, mainMysqlTransactionTemplate
-
其它参数说明。标准url配置条件下,本框架对数据库默认的编码是UTF-8(建议就用这个吧),如果有特殊要求,可以设置characterEncoding参数,如:
camel.mysql.main.characterEncoding=UTF-8
1.2.2、 Redis 使用说明
配置Redis的配置文件,样本如下:
camel.redis.query.hostName=127.0.0.1
camel.redis.query.port=6694
camel.redis.query.password=Youcai
camel.redis.query.poolConfig.testOnBorrow=true
camel.redis.query.poolConfig.testWhileIdle=true
camel.redis.query.poolConfig.minIdle=20
camel.redis.query.poolConfig.maxIdle=100
camel.redis.query.poolConfig.maxTotal=100
camel.redis.query.poolConfig.maxWaitMillis=100
上面配置的关键字是query
,将按这个关键字生成如下Bean,可根据实际情况选择注入使用:
queryRedisDataSource, queryRedisTemplate, queryCamelRedisTemplate
使用程序样本如下,建议注入queryCamelRedisTemplate
使用,如:
@Repository
public class RankImpl implements RankDao {
@Autowired
@Qualifier("queryCamelRedisTemplate")
RedisTemplate<String, String> queryCamelRedisTemplate;
final String rankKey = "rank";
@Override
public void updateRank(long uid, long score) {
queryCamelRedisTemplate.opsForZSet().add(rankKey, uid, score);
}
}
更多高级配置请参考JedisPoolConfig。
1.2.3、 Kafka 使用说明
Kafka配置分为生产者与消费者,下面将分别分开来讨论。
1.2.3.1、 Kafka Producer
下面是生产者的配置样本:
camel.kafka.producer.rank.topics=rank
camel.kafka.producer.rank.bootstrap.servers=127.0.0.1:9092
camel.kafka.producer.rank.acks=-1
camel.kafka.producer.rank.retries=3
camel.kafka.producer.rank.batch.size=100000
camel.kafka.producer.rank.client.id=sail_rank
上面配置的关键字是rank
,将按这个关键字生成如下Bean,可根据实际情况选择注入使用:
rankKafkaProducer, rankCamelKafkaProducer
使用程序样本如下,建议注入rankCamelKafkaProducer
使用,如:
@Component
@Slf4j
public class DemoProducerDaoImpl implements DemoProducerDao{
@Autowired
@Qualifier("rankCamelKafkaProducer")
private CamelKafkaProducer<String, String> rankCamelKafkaProducer;
public void send() {
String message = "{\"uid\":\"3452378\",\"score\":3500,\"mark\":\"gift\"}";
ProducerRecord<String, String> record = new ProducerRecord<>(rankCamelKafkaProducer.getTopics().get(0), UUID.randomUUID().toString(), message);
rankCamelKafkaProducer.send(record, (metadata, e) -> {
if (e != null) {
log.error("", e);
}
});
}
}
更多可配置参数请阅读类ProducerConfig。
1.2.3.2、 Kafka Consumer
下面是消费者的配置样本:
camel.kafka.consumer.weekRank.bootstrap.servers=10.10.10.1:9092,10.10.10.2:9092,10.10.10.3:9092
camel.kafka.consumer.weekRank.group.id=week_rank_consume_local
camel.kafka.consumer.weekRank.client.id=week_rank_consume_local
camel.kafka.consumer.weekRank.security.protocol=SASL_PLAINTEXT
camel.kafka.consumer.weekRank.sasl.mechanism=PLAIN
camel.kafka.consumer.weekRank.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="Youcai" password="demo";
camel.kafka.consumer.weekRank.enable.auto.commit=true
camel.kafka.consumer.weekRank.auto.commit.interval.ms=1000
camel.kafka.consumer.weekRank.max.poll.records=1000
上面配置的关键字是weekRank
,将按这个关键字生成如下Bean,可根据实际情况选择注入使用:
weekRankKafkaConsumer, weekRankCamelKafkaConsumer
使用程序样本如下,建议注入weekRankCamelKafkaConsumer
使用,如:
@Component
@Slf4j
public class DemoConsumer {
@Autowired
@Qualifier("weekRankCamelKafkaConsumer")
CamelKafkaConsumer<String, String> weekRankCamelKafkaConsumer;
@PostConstruct
public void execute() {
new Thread(() -> {
weekRankCamelKafkaConsumer.subscribe(weekRankCamelKafkaConsumer.getTopics());
while (true) {
try{
ConsumerRecords<String, String> records = weekRankCamelKafkaConsumer.poll(Duration.ofMillis(1000));
records.forEach(record -> {
String item = record.value();
log.info("consumer: {}", item);
});
} catch (Exception e) {
log.error("", e);
}
}
}).start();
}
}
可配置参数请阅读类ConsumerConfig,如果Kafka消费比较多的话,可以考虑使用ForkJoin并行的框架来消费消息,
详细见exmaple模块的DemoForkJoinConsumer
,这段代码作用非常牛的,我们项目基本都是使用这种方式来消费。
1.2.4、 Elasticsearch 使用说明
配置elasticsearch的配置文件,样本如下:
camel.elasticsearch.search.url=http://127.0.0.1:9200
camel.elasticsearch.search.username=x
camel.elasticsearch.search.password=x
camel.elasticsearch.search.maxConnTotal=15
camel.elasticsearch.search.maxConnPerRoute=35
定义好上面配置外,还要在项目的根pom.xml定义如下代码,否则将使用的是elasticsearch7.x的版本,如果你的项目就是7.x,也强烈建议再定义一次springboot预定义一样的版本号代码。
<elasticsearch.version>6.2.2</elasticsearch.version>
上面配置的关键字是search
,将按这个关键字生成如下Bean,可根据实际情况选择注入使用:
searchEsHighLevelClient
可配置参数请阅读类CamelESPooling
使用程序样本如下,注入searchEsHighLevelClient
使用,如:
@Service
public class SearchServiceImpl implements SearchService{
@Autowired
@Qualifier("searchTestEsHighLevelClient")
RestHighLevelClient searchEsHighLevelClient;
@Override
public SearchResponse search(String keyword) {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name", keyword)).size(10);
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(searchSourceBuilder);
try {
return searchEsHighLevelClient.search(searchRequest);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
Appendix
Spring Boot Reference Documentation:
https://docs.spring.io/spring-boot/docs/2.5.9/reference/html/
How-to Guides:
https://docs.spring.io/spring-boot/docs/2.5.9/reference/html/howto.html#howto.data-access
Core Technologies:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-nature
Spring Data JDBC - Reference Documentation:
https://docs.spring.io/spring-data/jdbc/docs/2.2.8/reference/html/#jdbc.repositories