GVKun编程网logo

ApacheBeam-Java:MongoDB 过滤器(mongodb 过滤查询)

16

本文将为您提供关于ApacheBeam-Java:MongoDB过滤器的详细介绍,我们还将为您解释mongodb过滤查询的相关知识,同时,我们还将为您提供关于ApacheBeamJavaSDK快速开始

本文将为您提供关于ApacheBeam-Java:MongoDB 过滤器的详细介绍,我们还将为您解释mongodb 过滤查询的相关知识,同时,我们还将为您提供关于Apache Beam Java SDK 快速开始、apache beam 初探--java篇、Apache Camel + MongoDB文档不正确?、Apache Commons BeanUtils: JavaBean操作的艺术的实用信息。

本文目录一览:

ApacheBeam-Java:MongoDB 过滤器(mongodb 过滤查询)

ApacheBeam-Java:MongoDB 过滤器(mongodb 过滤查询)

如何解决ApacheBeam-Java:MongoDB 过滤器?

我是数据流/Apchebeam 的新手。我正在从 MongoDB 中提取数据。 MongoDB 连接工作正常,但我无法应用过滤器。抛出以下错误。我不确定这是过滤数据的正确方法。任何建议都会有所帮助。

错误

2021-06-07 10:37:34.615 来自 worker 的 CESTError 消息:java.lang.classCastException:com.test.dataflow.dofns.MongodDbQueryFn 无法转换为 org.apache.beam.sdk.io。 mongodb.AggregationQuery org.apache.beam.sdk.io.mongodb.MongoDbIO$BoundedMongoDbSource.split(MongoDbIO.java:522)

代码:MongoDbIO 连接器:

return  pipeline.apply(MongoDbIO.read()                        
.withUri("mongodb://".concat(databaseDetails.getDatabaseHostName()).concat(":").concat(databaseDetails.getPort()))
.withDatabase(databaseDetails.getDatabaseName())
.withCollection(objectDetails.getobjectName())
.withQueryFn(new MongodDbQueryFn("name","Mahesh")));

QueryFn PTransform

package com.test.dataflow.dofns;
import org.apache.beam.sdk.transforms.SerializableFunction;
import org.bson.Document;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;

public class MongodDbQueryFn implements SerializableFunction<MongoCollection<Document>,MongoCursor<Document>> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private String keyName;
    private String keyvalue;

    public MongodDbQueryFn(String keyName,String keyvalue) {

        this.keyName = keyName;
        this.keyvalue = keyvalue;

    }

    @Override
    public MongoCursor<Document> apply(MongoCollection<Document> input) {
        return input.find(com.mongodb.client.model.Filters.eq(keyName,keyvalue)).iterator();
    }
    
}

解决方法

withQueryFn 的文档并没有很好地解释这一点,但是从通读代码到 MongoDbIO 看来,MongoDbIO.Read 假定 QueryFn 设置为 {{3 }} 或 AggregationQuery。您遇到的错误是因为代码正在检查 queryFn 是否为 FindQuery,结果为 false,然后假设它是 AggregationQuery 并尝试对其进行转换。

最适合您的解决方案是使用 FindQuery 获得与您编写的相同的行为,如下所示:

.withQueryFn(FindQuery.create().withFilters(Filters.eq("name","Mahesh"))));

Apache Beam Java SDK 快速开始

Apache Beam Java SDK 快速开始

原文链接:http://blog.geekidentity.com/beam/apache_beam_java_SDK_quickstart/

本快速入门将指导您完成第一个Beam pipeline,以便在您选择的runner 上运行使用Beam的Java SDK编写的WordCount。

  • 设置开发环境
  • 获取WordCount代码
  • 运行WordCount
  • 检查结果
  • 下一步

    设置开发环境

  1. 下载并安装Java 开发工具包(JDK)1.7或更高版本。 验证是否已设置JAVA_HOME环境变量并指向JDK 安装目录。
  2. 按照指定操作系统的Maven安装指南,下载并安装 Apache Maven。

获取WordCount代码

 

获取WordCount pipeline 拷贝的最简单方法是使用以下命令生成一个简单的Maven项目,其中包含Beam的WordCount示例,并针对最新的Beam版本进行构建:

 

1

2

3

4

5

6

7

8

9

10

 

$ mvn archetype:generate \

-DarchetypeRepository=https://repository.apache.org/content/groups/snapshots \

-DarchetypeGroupId=org.apache.beam \

-DarchetypeArtifactId=beam-sdks-java-maven-archetypes-examples \

-DarchetypeVersion=LATEST \

-DgroupId=org.example \

-DartifactId=word-count-beam \

-Dversion="0.1" \

-Dpackage=org.apache.beam.examples \

-DinteractiveMode=false

Maven 将创建目录word-count-beam,其中包含一个简单的pom.xml和一系列示例pipelines,用于文本文件中的字进行计数。

 

1

2

3

4

5

6

7

8

 

$ cd word-count-beam/

$ ls

pom.xml src

$ ls src/main/java/org/apache/beam/examples/

DebuggingWordCount.java WindowedWordCount.java common

MinimalWordCount.java WordCount.java

有关这些示例中使用的Beam概念的详细介绍,请参见WordCount示例演练。 这里,我们只关注执行WordCount.java。

运行WordCount

单个Beam pipeline 可以在Beam runners上运行,包括 ApexRunner, FlinkRunner, SparkRunner 和 DataflowRunner.。 DirectRunner是一个常用的入门指南,因为它在本地运行,不需要特殊的设置。

在选择要使用的runner 之后:

  1. 确保已完成任何特定于runner的设置。
  2. 构建命令行:
    1. 使用–runner = (默认为DirectRunner)指定特定runner
    2. 添加runner 运行所需的选项
    3. 选择runner 可以访问的输入文件和输出位置。 (例如,如果正在外部集群上运行pipeline ,则无法访问本地文件。)
  3. 运行你的第一个WordCount pipeline。
  4. 以Spark为例(其他示例请看官网文档):
 

1

2

 

$ mvn compile exec:java -Dexec.mainClass=org.apache.beam.examples.WordCount \

-Dexec.args="--runner=SparkRunner --inputFile=pom.xml --output=counts" -Pspark-runner

检查结果

一旦pipeline完成,你可以查看输出。 你会注意到可能有多个输出文件以count为前缀。 这些文件的确切数目由运行程序决定,使其能够灵活地执行高效的分布式执行。

 

1

 

$ ls counts*

当您查看文件的内容时,您会看到它们包含唯一字词和每个字词的出现次数。 文件中的元素的顺序可能不同,因为beam 模型通常不保证排序,以再次允许runner 优化效率。

 

1

2

3

4

5

6

7

8

9

10

 

$ more counts*

beam: 27

SF: 1

fat: 1

job: 1

limitations: 1

require: 1

of: 11

profile: 10

...

下一步

  • 在WordCount示例演练中了解有关这些WordCount示例的更多信息。
  • 深入了解我们最喜欢的文章和演示文稿。
  • 加入Beam 用户@邮件列表。

如果您遇到任何问题,请随时与我们联系!

apache beam 初探--java篇

apache beam 初探--java篇

 

——————————————
版权声明:本文为博主「henyu」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://i.cnblogs.com/EditPosts.aspx?postid=11430012

一 、概述
在大数据的浪潮之下,技术的更新迭代十分频繁。受技术开源的影响,大数据开发者提供了十分丰富的工具。但也因为如此,增加了开发者选择合适工具的难度。在大数据处理一些问题的时候,往往使用的技术是多样化的。这完全取决于业务需求,比如进行批处理的MapReduce,实时流处理的Flink,以及SQL交互的Spark SQL等等。而把这些开源框架,工具,类库,平台整合到一起,所需要的工作量以及复杂度,可想而知。这也是大数据开发者比较头疼的问题。而今天要分享的就是整合这些资源的一个解决方案,它就是 Apache Beam。

Beam是一个统一的编程框架,支持批处理和流处理,并可以将用Beam编程模型构造出来的程序,在多个计算引擎(Apache Apex, Apache Flink, Apache Spark, Google Cloud Dataflow等)上运行。

 

本文重点不在于讲解 apache beam 的优缺点及应用前景,着重在于为初识beam ,而不知道怎么入门编写代码的朋友抛转引玉。

二、apache beam 是什么

网上关于apache beam 的介绍很多,在这里我就不介绍了,有兴趣的可参阅下面链接

https://blog.csdn.net/qq_34777600/article/details/87165765 (原文出自: 一只IT小小鸟)

https://www.cnblogs.com/bigben0123/p/9590489.html (来源于 张海涛,目前就职于海康威视云基础平台,负责云计算大数据的基础架构设计和中间件的开发,专注云计算大数据方向。Apache Beam 中文社区发起人之一,如果想进一步了解最新 Apache Beam 动态和技术研究成果,请加微信 cyrjkj 入群共同研究和运用)

 

三 、代码入门

示例一 、读写文件 TextIO

 

<dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-sdks-java-core</artifactId>
            <version>${beam.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.beam/beam-runners-direct-java -->
        <dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-runners-direct-java</artifactId>
            <version>${beam.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
<dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-runners-core-java</artifactId>
            <version>${kafka.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>

 

/**
     * 读写文件 TextIO
     *
     * @param
     */
    public static void TextIo() {
        //创建管道工厂
        PipelineOptions pipelineOptions = PipelineOptionsFactory.create();
        //设置运行的模型,现在一共有3种
        pipelineOptions.setRunner(DirectRunner.class);
        //设置相应的管道
        Pipeline pipeline = Pipeline.create(pipelineOptions);
        //根据文件路径读取文件内容
        pipeline.apply(TextIO.read().from("C:\\bigdata\\apache_beam\\src\\main\\resources\\abc"))
                .apply("ExtractWords", ParDo.of(new DoFn<String, String>() {
                    @ProcessElement
                    public void processElement(ProcessContext c) {
                        //根据空格读取数据
                        for (String word : c.element().split(" ")) {
                            if (!word.isEmpty()) {
                                c.output(word);
                                System.out.println("读文件中的数据:" + word);
                            }
                        }
                    }
                })).apply(Count.<String>perElement())
                .apply("formatResult", MapElements.via(new SimpleFunction<KV<String, Long>, String>() {
                    @Override
                    public String apply(KV<String, Long> input) {
                        return input.getKey() + " : " + input.getValue();
                    }
                }))
                .apply(TextIO.write().to("C:\\bigdata\\apache_beam\\src\\main\\resources")); //进行输出到文件夹下面

        pipeline.run().waitUntilFinish();

    }

 

示例二、启用flink作为计算引擎、整合kafka ,以流式数据窗口的方式,计算kafka数据

引入相关依赖

<dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-sdks-java-core</artifactId>
            <version>${beam.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
 <dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-sdks-java-io-kafka</artifactId>
            <version>${beam.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>${kafka.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.beam/beam-runners-core-java -->
        <dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-runners-core-java</artifactId>
            <version>${kafka.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
<dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-java</artifactId>
            <version>${flink.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-clients_2.11</artifactId>
            <version>${flink.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-core</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-runtime_2.11</artifactId>
            <version>${flink.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-java_2.11</artifactId>
            <version>${flink.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-metrics-core</artifactId>
            <version>${flink.version}</version>
            <!--<scope>provided</scope>-->
        </dependency>

 

 

核心代码 :

/**
     * flink
     * 读写kafka数据
     * flinkRunner
     * @param
     */
    public static void flinkKafka() {
        FlinkPipelineOptions options = PipelineOptionsFactory.as(FlinkPipelineOptions.class);
        // 显式指定PipelineRunner:FlinkRunner必须指定如果不制定则为本地
        options.setStreaming(true);
        options.setAppName("app_test");
        options.setJobName("flinkjob");
        options.setFlinkMaster("local");
        options.setParallelism(10);
        //创建flink管道
        Pipeline pipeline = Pipeline.create(options);
        //指定KafkaIO的模型,从源码中不难看出这个地方的KafkaIO<K,V>类型是String和String 类型,也可以换成其他类型。
        PCollection<KafkaRecord<String, String>> lines =
                pipeline.apply(KafkaIO.<String, String>read()
                                //设置Kafka集群的集群地址
                                .withBootstrapServers(kafkaBootstrapServers)
                                //设置Kafka的主题类型,源码中使用了单个主题类型,如果是多个主题类型则用withTopics(List<String>)方法进行设置。
                                // 设置情况基本跟Kafka原生是一样的
                                .withTopic(inputTopic)
                                //设置序列化类型
                                .withKeyDeserializer(StringDeserializer.class)
                                .withValueDeserializer(StringDeserializer.class)
                                //设置Kafka的消费者属性,这个地方还可以设置其他的属性。源码中是针对消费分组进行设置。
                                .withConsumerConfigUpdates(ImmutableMap.<String, Object>of("auto.offset.reset", "latest"))
                /*//设置Kafka吞吐量的时间戳,可以是默认的,也可以自定义
                .withLogAppendTime()
                *//**
                         * 相当于Kafka 中"isolation.level", "read_committed" ,指定KafkaConsumer只应读取非事务性消息,或从其输入主题中提交事务性消息。
                         * 流处理应用程序通常在多个读取处理写入阶段处理其数据,每个阶段使用前一阶段的输出作为其输入。
                         * 通过指定read_committed模式,我们可以在所有阶段完成一次处理。针对"Exactly-once" 语义,支持Kafka 0.11版本。
                         *//*
                .withReadCommitted()
                //设置Kafka是否自动提交属性"AUTO_COMMIT",默认为自动提交,使用Beam 的方法来设置
                .commitOffsetsInFinalize()
                //设置是否返回Kafka的其他数据,例如offset 信息和分区信息,不用可以去掉
                .withoutMetadata()
                //设置只返回values值,不用返回key*/
                );

        //kafka数据获取
        PCollection<String> kafkadata = lines.apply("Remove Kafka Metadata", ParDo.of(new DoFn<KafkaRecord<String, String>, String>() {
            @ProcessElement
            public void processElement(ProcessContext c) {
                System.out.println("输出的分区为----:" + c.element().getKV());
                c.output(c.element().getKV().getValue());
            }
        }));

       //kafka数据处理
        PCollection<String> wordCount = kafkadata
                .apply(Window.<String>into(FixedWindows.of(Duration.standardSeconds(5))))
                .apply(Count.<String>perElement())
                .apply("ConcatResultKV", MapElements.via(new SimpleFunction<KV<String, Long>, String>() {
                    // 拼接最后的格式化输出(Key为Word,Value为Count)
                    @Override
                    public String apply(KV<String, Long> input) {
                        System.out.println("进行统计:" + input.getKey() + ": " + input.getValue());
                        return input.getKey() + ": " + input.getValue();
                    }
                }));
        //kafka 处理后的数据发送回kafka
        wordCount.apply(KafkaIO.<Void, String>write()
                        .withBootstrapServers(kafkaBootstrapServers)
                        .withTopic(outputTopic)
                        //不需要设置,类型为void
//                .withKeySerializer(VoidDeserializer.class)
                        .withValueSerializer(StringSerializer.class)
                        .values()
        );
        pipeline.run().waitUntilFinish();

    }

 

示例三 :spark作为runner ,读取kafka流式数据,窗口时间,处理结果放回kafka

依赖 ,将示例二差不多

<dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-runners-spark</artifactId>
            <version>${beam.version}</version>
        </dependency>

核心代码

/**
     * 采用spark 作为runner
     * 消费kafka数据
     */
    public static void sparkKafka() {
        //创建管道工厂
        SparkPipelineOptions options = PipelineOptionsFactory.as(SparkPipelineOptions.class);
        //参数设置
        options.setSparkMaster("local[*]");
        options.setAppName("spark-beam");
        options.setCheckpointDir("/user/chickpoint16");
        //创建管道
        Pipeline pipeline = Pipeline.create(options);
        //读取kafka数据
        PCollection<KafkaRecord<String, String>> lines = pipeline.apply(KafkaIO.<String, String>read()
                //设置kafka地址
                .withBootstrapServers(kafkaBootstrapServers)
                //设置连接主题
                .withTopic(inputTopic)
                //设置序列化
                .withKeyDeserializer(StringDeserializer.class)
                .withValueDeserializer(StringDeserializer.class)
                //设置Kafka的消费者属性,这个地方还可以设置其他的属性。源码中是针对消费分组进行设置。
                .withConsumerConfigUpdates(ImmutableMap.<String, Object>of("auto.offset.reset", " latest"))

        );
       //数据处理
        PCollection<String> wordcount = lines.apply("split data",ParDo.of(new DoFn<KafkaRecord<String, String>,String>() {
            @ProcessElement
            public void processElement(ProcessContext c){
                String[] arr=c.element().getKV().getValue().split(" ");
                for(String value :arr){
                    if(!value.isEmpty()){
                        c.output(value);
                    }
                }

            }
        })).apply(Window.<String>into(FixedWindows.of(Duration.standardSeconds(5))))
                .apply(Count.<String>perElement())
                .apply("wordcount",MapElements.via(new SimpleFunction<KV<String,Long>,String>(){
                    @Override
                    public String apply(KV<String,Long> input){
                        System.out.println(input.getKey()+" : "+input.getValue());
                        System.err.println("===============================================");
                        return input.getKey()+" : "+input.getValue();
                    }
                }));
        System.out.println(wordcount);
        //kafka 处理后的数据发送回kafka
        wordcount.apply(KafkaIO.<Void, String>write()
                .withBootstrapServers(kafkaBootstrapServers)
                .withTopic(outputTopic)
                .withValueSerializer(StringSerializer.class)
                .values()
        );
        pipeline.run().waitUntilFinish();

    }

 

示例四 :HBaseIO

依赖

<dependency>
            <groupId>org.apache.beam</groupId>
            <artifactId>beam-sdks-java-io-hbase</artifactId>
            <version>${beam.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>${hbase.version}</version>
        </dependency>

 

代码 :

/**
     * HBaseIo beam
     * 采用apache beam的方式读取hbase 数据
     */
    public static void  getHbaseData(){
        //创建管道工厂
//        SparkPipelineOptions options = PipelineOptionsFactory.as(SparkPipelineOptions.class);
//        options.setJobName("read mongo");
//        options.setSparkMaster("local[*]");
//        options.setCheckpointDir("/user/chickpoint17");
        PipelineOptions options = PipelineOptionsFactory.create();
        options.setRunner(DirectRunner.class);
        config = HBaseConfiguration.create();
        config.set("hbase.zookeeper.property.clientPort", hbase_clientPort);
        config.set("hbase.zookeeper.quorum", hbase_zookeeper_quorum);
        config.set("zookeeper.znode.parent", zookeeper_znode_parent);
        config.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
        config.setInt("hbase.rpc.timeout", 20000);
        config.setInt("hbase.client.operation.timeout", 30000);
        config.setInt("hbase.client.scanner.timeout.period", 2000000);
        //创建管道
        Pipeline pipeline = Pipeline.create(options);
        PCollection<Result> result = pipeline.apply(HBaseIO.read()
                .withConfiguration(config)
                .withTableId(hbase_table)
                .withKeyRange("001".getBytes(),"004".getBytes())
        );
        PCollection<String> process = result.apply("process", ParDo.of(new DoFn<Result, String>() {
            @ProcessElement
            public void processElement(ProcessContext c) {
                String row = Bytes.toString(c.element().getRow());
                List<Cell> cells = c.element().listCells();
                for (Cell cell:cells){
                    String family = Bytes.toString(cell.getFamilyArray(),cell.getFamilyLength(),cell.getFamilyOffset());
                    String column = Bytes.toString(cell.getQualifierArray(),cell.getQualifierOffset(),cell.getQualifierLength());
                    String value= Bytes.toString(cell.getValueArray(),cell.getValueOffset(),cell.getValueLength());
                    System.out.println(family);
                    c.output(row+"------------------ "+family+" : "+column+" = "+value);
                    System.out.println(row+"------------------ "+family+" : "+column+" = "+value);
                }
            }
        }));

        pipeline.run().waitUntilFinish();
    }

 

四:说明

apache beam 目前处于孵化状态,目前对java的支持较好,python 等语言支持还待完善。故有兴趣的朋友最好选择java学习。

 

Apache Camel + MongoDB文档不正确?

Apache Camel + MongoDB文档不正确?

如何解决Apache Camel + MongoDB文档不正确??

我正在阅读using findOneByQuery using Apache Camel + MongoDB上的说明,并且认为我正在按照它的意思做

import com.mongodb.client.model.Filters;
import deletion.manager.Constants;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mongodb.MongoDbConstants;
import org.springframework.stereotype.Component;

@Component
public class NotifyClientRoute extends RouteBuilder {
// ...
    @Override
    public void configure() throws Exception {

      from("direct:findOneByQuery")
        .setHeader(MongoDbConstants.CRITERIA,Filters.eq("name","Raul Kripalani"))
        .to("mongodb:myDb?database=flights&collection=tickets&operation=findOneByQuery")
        .to("mock:resultFindOneByQuery");
         

我收到此编译错误:

无法解析方法''setHeader(java.lang.String,org.bson.conversions.Bson)''

我尝试寻找其他/更好的示例,但找不到任何示例。 setHeader的选项是:

#setHeader(String name)
#setHeader(String name,Expression expression)
#setHeader(String name,supplier<Object>)

我很确定我要导入正确的类。我不想创建一个简单的Bean类,只是可以@AutowiredMongoTemplate,但这似乎是我目前唯一的选择。有任何想法吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Apache Commons BeanUtils: JavaBean操作的艺术

Apache Commons BeanUtils: JavaBean操作的艺术

第1部分:Apache Commons BeanUtils 简介

咱们今天聊聊Apache Commons BeanUtils。这货简直就是处理JavaBean的利器,用起来又方便又快捷。不管是属性拷贝、类型转换,还是动态访问,BeanUtils都能轻松应对。

BeanUtils是啥?

Apache Commons BeanUtils,简单来说,就是一套Java库,专门用来操作JavaBeans。什么是JavaBeans?嗯,它其实就是遵循特定规范的Java类,比如有无参构造器、属性私有、公共的getter和setter方法。这些Beans在Java世界里可是处处可见,无论是Web开发还是桌面应用,它们都扮演着重要角色。

为啥要用BeanUtils?

小黑告诉你,操作JavaBean虽然不难,但手动去写一堆getter和setter,是不是觉得有点啰嗦?特别是要处理一堆类似的操作,比如复制属性啊,类型转换啊,这时候,BeanUtils就闪亮登场了。它能让这些操作变得简单快捷,代码更加整洁,提高开发效率。

怎么用起来?

先来看看如何把BeanUtils加入到咱们的项目里。一般来说,用Maven或者Gradle这样的构建工具是最方便的。例如,用Maven的话,只需在pom.xml文件里添加如下依赖:

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.4</version> <!-- 使用最新稳定版本 -->
</dependency>

加完这个依赖后,咱们就可以在项目中自由使用BeanUtils的各种功能了。

第2部分:核心功能概览

PS: 小黑收集整理了一份超级全面的复习面试资料包,在这偷偷分享给你~ 点击这里立即领取!

PropertyUtils:操控属性的基础

PropertyUtils主要用来操作Bean的属性。比如说,咱们可以通过它来获取或设置属性的值。它更像是BeanUtils的基石,为BeanUtils提供了基本的属性操作功能。

BeanUtils:PropertyUtils的超级版

如果说PropertyUtils是基础版,那BeanUtils就是加强版。它在PropertyUtils的基础上增加了很多实用的功能,比如属性的复制。这可是在实际开发中超级常用的。

ConvertUtils:类型转换的神器

在处理JavaBean的时候,经常会遇到属性类型转换的需求。这时候,ConvertUtils就能派上用场了。它能自动帮咱们处理各种类型之间的转换,省心省力。

代码示例:基本使用

来,咱们看个简单的例子。假设有个人物类(Person),小黑用BeanUtils给它设置属性。

import org.apache.commons.beanutils.BeanUtils;

public class Demo {
    public static void main(String[] args) {
        Person person = new Person();
        try {
            // 使用BeanUtils设置属性
            BeanUtils.setProperty(person, "name", "张三");
            BeanUtils.setProperty(person, "age", 30);

            // 获取并打印属性
            String name = BeanUtils.getProperty(person, "name");
            String age = BeanUtils.getProperty(person, "age");
            System.out.println("姓名: " + name + ", 年龄: " + age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Person {
    private String name;
    private int age;
    // 省略getter和setter方法
}

在这个例子中,咱们用BeanUtils给Person类的name和age属性赋值,然后又获取这些值并打印出来。

第3部分:深入PropertyUtils

PropertyUtils的核心功能

PropertyUtils主要提供了读取和设置JavaBean属性的功能。这听起来很基础,但在实际开发中却非常有用。举个例子,如果咱们需要从一个对象中读取某个属性的值,或者要把值设置到对象的某个属性上,用PropertyUtils就能轻松搞定。

读取属性:获取的艺术

咱们来看看如何使用PropertyUtils读取属性值。假设有个User类,有nameage这两个属性,小黑现在要读取这些属性的值。

import org.apache.commons.beanutils.PropertyUtils;

public class PropertyUtilsDemo {
    public static void main(String[] args) {
        User user = new User();
        user.setName("李雷");
        user.setAge(25);

        try {
            // 读取属性值
            String name = (String) PropertyUtils.getProperty(user, "name");
            Integer age = (Integer) PropertyUtils.getProperty(user, "age");
            System.out.println("姓名: " + name + ", 年龄: " + age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class User {
    private String name;
    private int age;

    // 省略getter和setter方法
}

在这个例子中,小黑通过PropertyUtils.getProperty方法轻松获取了User对象的nameage属性值。

设置属性:赋值的智慧

接下来,如果咱们想要设置对象的属性值,PropertyUtils同样能派上用场。比如小黑现在要把Username改成“韩梅梅”,age改成30。

public class PropertyUtilsDemo {
    public static void main(String[] args) {
        User user = new User();

        try {
            // 设置属性值
            PropertyUtils.setProperty(user, "name", "韩梅梅");
            PropertyUtils.setProperty(user, "age", 30);

            // 验证结果
            System.out.println("姓名: " + user.getName() + ", 年龄: " + user.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // User类和前面一样,这里就不重复了
}

在这个例子里,小黑用PropertyUtils.setProperty方法给User对象的属性赋了新值,然后打印出来,确保一切正常。

动态属性操作:灵活性的体现

PropertyUtils的魔力还不止于此。它还支持动态属性操作,这意味着咱们可以在运行时动态地读取和设置属性,而不必在编码时就确定属性名。这在处理动态数据结构时特别有用。

import java.util.HashMap;
import java.util.Map;

public class DynamicPropertyDemo {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("username", "小明");
        map.put("age", 20);

        try {
            // 动态读取属性
            String username = (String) PropertyUtils.getProperty(map, "username");
            Integer age = (Integer) PropertyUtils.getProperty(map, "age");
            System.out.println("用户名: " + username + ", 年龄: " + age);

            // 动态设置属性
            PropertyUtils.setProperty(map, "age", 21);
            System.out.println("更新后年龄: " + map.get("age"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,小黑创建了一个Map,然后用PropertyUtils来动态地处理这个Map中的数据。这样的灵活性在处理JSON数据或者动态表单数据时特别有优势。

第4部分:BeanUtils的高级应用

现在小黑要和大家探讨的是BeanUtils的一些高级应用,特别是属性复制和动态Bean操作。这些功能在实际开发中非常有用,可以让代码更加简洁和高效。

属性复制:简化数据迁移

属性复制是BeanUtils的一大亮点。在实际开发中,经常会遇到从一个对象复制属性到另一个对象的场景,尤其是在处理类似DTO(数据传输对象)和Entity(实体)转换的时候。如果手动一个属性一个属性地复制,既麻烦又容易出错。这时候,BeanUtils的copyProperties方法就能大显身手了。

看看小黑怎么用这个功能:

import org.apache.commons.beanutils.BeanUtils;

public class CopyPropertiesDemo {
    public static void main(String[] args) {
        UserDTO userDTO = new UserDTO("王小明", 28);
        UserEntity userEntity = new UserEntity();

        try {
            // 从DTO复制到实体
            BeanUtils.copyProperties(userEntity, userDTO);

            // 验证结果
            System.out.println("用户实体:姓名 - " + userEntity.getName() + ", 年龄 - " + userEntity.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class UserDTO {
    private String name;
    private int age;

    UserDTO(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 省略getter和setter方法
}

class UserEntity {
    private String name;
    private int age;

    // 省略getter和setter方法
}

在这个例子中,小黑从一个UserDTO对象复制属性到UserEntity对象。这样一来,所有的属性就自动从DTO转移到实体上了,省时省力。

动态Bean操作:更多的可能性

动态Bean操作是BeanUtils中另一个很酷的功能。它允许咱们在运行时动态创建和操作Bean,这在处理不确定的数据结构或者动态生成对象的场景下特别有用。

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.LazyDynaBean;
import org.apache.commons.beanutils.LazyDynaClass;

public class DynamicBeanDemo {
    public static void main(String[] args) {
        // 创建一个动态Bean
        DynaClass dynaClass = new LazyDynaClass();
        DynaBean dynaBean = new LazyDynaBean(dynaClass);

        try {
            // 动态添加属性
            dynaBean.set("name", "李华");
            dynaBean.set("age", 30);

            // 读取属性值
            String name = (String) dynaBean.get("name");
            Integer age = (Integer) dynaBean.get("age");
            System.out.println("动态Bean:姓名 - " + name + ", 年龄 - " + age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这个例子里,小黑创建了一个动态Bean,然后给它添加了nameage两个属性。这种方式的灵活性非常高,可以根据需要动态定义和操作对象的属性。

第5部分:ConvertUtils的威力

ConvertUtils,这个小玩意儿主要负责类型转换,特别是在处理JavaBean的属性时,经常会遇到需要把一种类型转换成另一种类型的情况。ConvertUtils就是用来解决这类问题的。

类型转换:简化而高效

在Java开发中,类型转换无处不在。比如从字符串转换成整数,或者从整数转换成布尔值等等。这些操作听起来简单,但如果每次都手动写转换代码,不仅麻烦,而且容易出错。ConvertUtils提供了一种统一的解决方案,可以自动完成这些转换,简化开发流程。

使用ConvertUtils进行基本转换

来看看ConvertUtils的基本使用方法。假设小黑现在有个字符串表示的年龄,需要把它转换成整数类型。

import org.apache.commons.beanutils.ConvertUtils;

public class ConvertUtilsDemo {
    public static void main(String[] args) {
        // 字符串转换为整数
        String ageStr = "25";
        Integer age = (Integer) ConvertUtils.convert(ageStr, Integer.class);
        System.out.println("转换后的年龄: " + age);
    }
}

在这个例子中,小黑使用了ConvertUtils的convert方法,轻松地把字符串"25"转换成了整数。

自定义类型转换器

但ConvertUtils的真正魅力在于它的可扩展性。如果咱们需要处理一些特殊的转换,比如把字符串转换成日期类型,或者把数字转换成自定义的枚举类型,这时就可以自定义转换器。

import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateTimeConverter;

public class CustomConverterDemo {
    public static void main(String[] args) {
        // 自定义转换器:字符串转日期
        DateTimeConverter dtConverter = new DateTimeConverter() {
            @Override
            protected Class<?> getDefaultType() {
                return java.util.Date.class;
            }
        };
        ConvertUtils.register(dtConverter, java.util.Date.class);

        // 使用自定义转换器
        String dateStr = "2023-12-25";
        java.util.Date date = (java.util.Date) ConvertUtils.convert(dateStr, java.util.Date.class);
        System.out.println("转换后的日期: " + date);
    }
}

在这个例子里,小黑注册了一个自定义的日期转换器,用来把字符串转换成java.util.Date类型。这样的自定义转换器让ConvertUtils的功能更加强大和灵活。

综合案例:处理复杂转换

实际开发中,咱们可能会遇到更复杂的转换需求。比如,有一个用户信息的字符串,里面包含了姓名、年龄和生日,咱们需要把这些信息提取出来,转换成相应的数据类型。

public class ComplexConversionDemo {
    public static void main(String[] args) {
        // 假设有这样一个用户信息字符串
        String userInfo = "张三,30,1993-04-15";

        // 分割字符串
        String[] parts = userInfo.split(",");

        // 转换各个部分
        String name = parts[0];
        Integer age = (Integer) ConvertUtils.convert(parts[1], Integer.class);
        java.util.Date birthday = (java.util.Date) ConvertUtils.convert(parts[2], java.util.Date.class);

        // 输出结果
        System.out.println("姓名: " + name + ", 年龄: " + age + ", 生日: " + birthday);
    }
}

在这个例子中,小黑处理了一个包含多种数据类型的字符串,并且使用ConvertUtils轻松完成了类型转换。

第6部分:性能分析

性能

虽然BeanUtils提供了很多便利的功能,但这些功能的背后可能会有一定的性能代价。例如,在复制大量属性或频繁操作Bean时,性能问题可能会浮现。这不是说BeanUtils性能差,而是任何便捷的功能都可能有性能成本,了解这一点对于写出高效的代码很重要。

BeanUtils的性能分析

BeanUtils在进行属性复制或类型转换时,会使用反射机制。反射机制虽然提供了极大的灵活性,但与直接访问属性相比,它在性能上通常会慢一些。这是因为反射需要在运行时解析类的元数据,这个过程比直接执行编译过的Java代码要慢。

实际应用中的考量

  • 数据量和频率:在处理小量数据或不频繁的操作时,BeanUtils带来的性能影响可以忽略不计。但在大批量数据处理或高频调用场景下,性能差异可能变得显著。
  • 功能与性能的平衡:在选择使用BeanUtils时,需要权衡其提供的便利性和可能的性能代价。如果性能是关键因素,可能需要考虑替代方案或优化代码。

第7部分:最佳实践和常见错误

最佳实践

  1. 合理使用反射:BeanUtils依赖于反射来操作JavaBean的属性。虽然反射很强大,但也不是万能的。在性能敏感的场景下,考虑直接使用getter和setter方法。
  2. 避免过度依赖:虽然BeanUtils可以简化很多操作,但并不意味着所有属性操作都应该通过它来完成。评估每种情况,如果手动操作更简单明了,就没必要强行使用BeanUtils。
  3. 处理异常:BeanUtils的方法可能会抛出异常。妥善处理这些异常,不仅可以避免程序崩溃,还能帮助定位问题。
  4. 自定义转换器的使用:当遇到BeanUtils内置转换器无法满足需求时,可以自定义转换器。但要确保自定义转换器的正确性和效率。
  5. 利用缓存提高性能:如果在高频率操作的场景中使用BeanUtils,考虑使用缓存机制来存储反射结果,以提高性能。

常见错误

  1. 忽略了null值的处理:在复制属性时,BeanUtils会将源对象的null值也复制过去。在某些情况下,这可能会覆盖目标对象的现有值。要特别注意这一点。
  2. 不正确的数据类型:在使用ConvertUtils进行类型转换时,如果源数据类型和目标数据类型不匹配,可能会导致转换错误或数据丢失。
  3. 反射性能问题:忽视BeanUtils基于反射的特性可能会导致性能问题,特别是在大数据量或高频率操作的场景中。
  4. 异常处理不当:BeanUtils操作可能会抛出多种异常。忽略这些异常的正确处理,可能会导致程序中断或隐蔽的bug。

第8部分:总结

在这篇博客中,我们深入探讨了Apache Commons BeanUtils库,一个在Java开发中不可或缺的工具。从基本介绍到高级应用,本文全面覆盖了BeanUtils的核心功能,包括PropertyUtils和ConvertUtils的使用,突出了它们在处理JavaBean属性时的便利性和灵活性。

我们首先概述了BeanUtils的基础知识,强调了它在简化JavaBean操作中的作用。随后,详细探讨了PropertyUtils和BeanUtils的高级功能,如属性复制和动态Bean操作,展示了它们如何在数据转换和处理中提供高效的解决方案。特别是在涉及自定义类型转换器和处理复杂类型转换的场景中,BeanUtils显示出其强大的功能。

最后希望大家能够学有所获,提升效率,简化开发!


面对寒冬,更需团结!小黑整理了超级强大的复习面试资料包,也强烈建议你加入我们的Java后端报团取暖群,一起复习,共享各种学习资源,分享经验,闲聊副业,进群方式以及资料,点击这里立即领取!

今天的关于ApacheBeam-Java:MongoDB 过滤器mongodb 过滤查询的分享已经结束,谢谢您的关注,如果想了解更多关于Apache Beam Java SDK 快速开始、apache beam 初探--java篇、Apache Camel + MongoDB文档不正确?、Apache Commons BeanUtils: JavaBean操作的艺术的相关知识,请在本站进行查询。

本文标签: