运行flink官网DataStream API例子报错ClassNotFoundException

今天在运行 flink官网DataStream API例子(一个针对可疑信用卡交易行为的反欺诈检测系统的demo :https://ci.apache.org/projects/flink/flink-docs-release-1.10/getting-started/walkthroughs/datastream_api.html)报错:

java.lang.ClassNotFoundException: org.apache.flink.streaming.api.functions.source.SourceFunction

1
2
3
4
5
6
7
8
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/flink/streaming/api/functions/source/SourceFunction
    at spendreport.FraudDetectionJob.main(FraudDetectionJob.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.flink.streaming.api.functions.source.SourceFunction
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

解决办法是将pom中将scope=provided的依赖改为compile即可。也可以利用maven的profiles标签,针对不同的开发环境,配置不同的环境。

在原来的pom.xml文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!-- 关键配置 -->
    <!-- 1. scope = provided 包需复制一份添加到下面的 dependencies,用于本地环境运行,scope 修改为 compile -->
    <!-- 2. IntelliJ IDEA maven 右上角profiles 勾选上 dev 线上打包请勿勾选-->
    <profiles>
        <!--用于生产环境打包-->
        <profile>
            <id>prod</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <profileActive>prod</profileActive>
            </properties>
        </profile>
        <!--用于测试环境打包-->
        <profile>
            <id>test</id>
            <properties>
                <profileActive>test</profileActive>
            </properties>
        </profile>
        <!--用于本地运行环境-->
        <profile>
            <id>dev</id>
            <activation>
                <property>
                    <name>idea.version</name>
                </property>
            </activation>
            <properties>
            <!-- dev 使用 test resources 目录,只是多了依赖 -->
            <profileActive>test</profileActive>
        </properties>

            <dependencies>
                <!--注释掉<scope>provided</scope>
                或者修改为compile ,否则程序会报ClassNotFoundException:
                org.apache.flink.streaming.api.functions.source.SourceFunction错误-->
                <dependency>
                    <groupId>org.apache.flink</groupId>
                    <artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
                    <version>${flink.version}</version>
                    <scope>compile</scope>
                    <!--<scope>provided</scope>-->
                </dependency>

            </dependencies>
        </profile>
    </profiles>

下面解释下providedcompile的区别,

对于compile是默认的scope,设置为scope=compile的依赖jar,项目在编译,测试,运行阶段都需要这个artifact对应的jar包在classpath中。

对于配置了provided的依赖,只影响到编译,测试阶段。在运行阶段如果程序运行的目标容器中没有这个jar包,运行就会报错,找不到这个类,而编译是会通过的。而在实际生产环境中,某些jar包,比如这里的flink-streaming-scala_${scala.binary.version} ,生产环境中肯定存在了,所以设置为provided,不需要将该依赖项,打包到jar文件中。而本地运行环境没有这个jar包,所以需要设置为compile