Camel Spring Boot框架(面向全球开源)

English Version

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,可根据实际情况选择注入即可马上使用, 建议注入mainCamelJdbcTemplatemainNamedParameterJdbcTemplate使用。

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