【问题标题】:How can i use blob storage from an azure function in Java如何在 Java 中使用 azure 函数中的 blob 存储
【发布时间】:2017-10-20 02:07:28
【问题描述】:

我有一个 http 触发的 azure 函数(用 Java 编写),我想在其中访问 Blob 存储。代码在 maven 下编译,但是当我在本地运行它并从 CURL 发送帖子时,运行时由于缺少 com.microsoft.azure.storage.CloudStorageAccount 导致的 ClassNotFound 异常而崩溃。 azure-storage(版本 6.0.0)在 POM 文件中列为依赖项。相关的 .jar 文件应该放在哪里才能被函数看到?

我们将不胜感激有关 Java azure 函数的任何见解。

【问题讨论】:

    标签: java azure azure-functions


    【解决方案1】:

    根据您的需要,我建议您按照此official tutorial 创建、运行和部署您的java azure function

    函数类:

    package com.fabrikam.functions;
    
    import com.microsoft.azure.serverless.functions.annotation.*;
    import com.microsoft.azure.serverless.functions.ExecutionContext;
    
    import com.microsoft.azure.storage.*;
    import com.microsoft.azure.storage.blob.*;
    
    /**
     * Hello function with HTTP Trigger.
     */
    public class Function {
    
        // Configure the connection-string with your values
        public static final String storageConnectionString =
                "DefaultEndpointsProtocol=http;" +
                        "AccountName=***;" +
                        "AccountKey=***";
    
        @FunctionName("hello")
        public String hello(@HttpTrigger(name = "req", methods = {"get", "post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req,
                            ExecutionContext context) {
    
            try {
                // Retrieve storage account from connection-string.
                CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
    
                // Create the blob client.
                CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
    
                // Get a reference to a container.
                // The container name must be lower case
                CloudBlobContainer container = blobClient.getContainerReference(req);
    
                // Create the container if it does not exist.
                container.createIfNotExists();
    
                return String.format("Hello, I get container name : %s!", container.getName());
    
            } catch (Exception e) {
                // Output the stack trace.
                e.printStackTrace();
                return "Access Error!";
            }
        }
    }
    

    Pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             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>com.fabrikam.functions</groupId>
        <artifactId>fabrikam-functions</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>Azure Java Functions</name>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <functionAppName>fabrikam-functions-20171017112209094</functionAppName>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.microsoft.azure</groupId>
                <artifactId>azure-functions-java-core</artifactId>
                <version>1.0.0-beta-1</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage -->
            <dependency>
                <groupId>com.microsoft.azure</groupId>
                <artifactId>azure-storage</artifactId>
                <version>6.0.0</version>
            </dependency>
    
            <!-- Test -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <artifactId>maven-resources-plugin</artifactId>
                        <version>3.0.2</version>
                    </plugin>
                    <plugin>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-functions-maven-plugin</artifactId>
                        <version>0.1.4</version>
                    </plugin>
                </plugins>
            </pluginManagement>
    
            <plugins>
                <plugin>
                    <groupId>com.microsoft.azure</groupId>
                    <artifactId>azure-functions-maven-plugin</artifactId>
                    <configuration>
                        <resourceGroup>java-functions-group</resourceGroup>
                        <appName>${functionAppName}</appName>
                        <region>westus2</region>
                        <appSettings>
                            <property>
                                <name>FUNCTIONS_EXTENSION_VERSION</name>
                                <value>beta</value>
                            </property>
                        </appSettings>
                    </configuration>
                    <executions>
                        <execution>
                            <id>package-functions</id>
                            <goals>
                                <goal>package</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>copy-resources</id>
                            <phase>package</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <overwrite>true</overwrite>
                                <outputDirectory>${project.build.directory}/azure-functions/${functionAppName}
                                </outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>${project.basedir}</directory>
                                        <includes>
                                            <include>host.json</include>
                                            <include>local.settings.json</include>
                                        </includes>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
    
        </build>
    
    </project>
    

    然后使用命令mvn clean package将你的maven项目打包成jar包。

    使用命令 mvn azure-functions:run 在本地运行您的 azure 函数。


    更新答案:

    我运行了我的天蓝色函数并重现了与您所说的相同的异常。

    java.lang.NoClassDefFoundError: com/microsoft/azure/storage/CloudStorageAccount

    Exception:
    Stack: java.lang.reflect.InvocationTargetException
    [10/25/2017 2:48:44 AM]         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [10/25/2017 2:48:44 AM]         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    [10/25/2017 2:48:44 AM]         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[10/25/2017 2:48:44 AM]         at java.lang.reflect.Method.invoke(Method.java:498)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.broker.JavaMethodInvokeInfo.invoke(JavaMethodInvokeInfo.java:19)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.broker.JavaMethodExecutor.execute(JavaMethodExecutor.java:34)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.broker.JavaFunctionBroker.invokeMethod(JavaFunctionBroker.java:40)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:33)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:10)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.handler.MessageHandler.handle(MessageHandler.java:41)
    [10/25/2017 2:48:44 AM]         at com.microsoft.azure.webjobs.script.JavaWorkerClient$StreamingMessagePeer.lambda$onNext$0(JavaWorkerClient.java:84)
    [10/25/2017 2:48:44 AM]         at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
    [10/25/2017 2:48:44 AM]         at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    [10/25/2017 2:48:44 AM]         at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    [10/25/2017 2:48:44 AM]         at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    [10/25/2017 2:48:44 AM]         at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
    [10/25/2017 2:48:44 AM] Caused by: java.lang.NoClassDefFoundError: com/microsoft/azure/storage/CloudStorageAccount
    [10/25/2017 2:48:44 AM]         at com.fabrikam.functions.Function.hello(Function.java:26)
    [10/25/2017 2:48:44 AM]         ... 16 more
    [10/25/2017 2:48:44 AM] Caused by: java.lang.ClassNotFoundException: com.microsoft.azure.storage.CloudStorageAccount
    [10/25/2017 2:48:44 AM]         at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    [10/25/2017 2:48:44 AM]         at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    [10/25/2017 2:48:44 AM]         at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    [10/25/2017 2:48:44 AM]         ... 17 more
    [10/25/2017 2:48:44 AM] .
    [10/25/2017 2:48:44 AM]   Function had errors. See Azure WebJobs SDK dashboard for details. Instance ID is '3450abda-99a0-4d75-add2-a7bc48a0cb51'
    [10/25/2017 2:48:44 AM] System.Private.CoreLib: Exception while executing function: Functions.hello. System.Private.CoreLib: Result:
    

    经过一番研究,发现是因为jar包没有dependent jar packages

    所以,我将如下配置的 sn-p 添加到我的pom.xml

    <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
                                <mainClass>Your main class path</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
    

    然后请使用命令mvn-clean-package,你会看到生成了两个jar文件。

    一个是不包含dependent jar packages,第二个是包含dependent jar packages

    fabrikam-functions-1.0-SNAPSHOT-jar-with-dependencies jar 移动到路径中:${project.basedir}/target/azure-functions/${function-app-name}/

    对我来说,它看起来像E:\TestAzureFunction\fabrikam-functions\target\azure-functions\fabrikam-functions-20171017112209094

    不要忘记将 jar 重命名为 fabrikam-functions-1.0-SNAPSHOT

    最后,我成功运行azure函数,通过url得到输出结果:http://localhost:7071/api/mongo

    另外,你可以参考这个github doc了解更多关于azure function maven plugin的配置细节。

    希望对你有帮助。

    【讨论】:

    • 我想你会发现,如果你真的执行你的函数(上面显示的只是表示函数已加载),它会崩溃并出现与我遇到的相同的错误。使用 CURL 向其发送 HTTP 消息。如果它没有崩溃,那么请告诉我 MS 存储库在您的本地计算机上的位置。
    • 我很好奇您是否能够使用 CURL 运行您的函数。我能够在本地创建和运行一个 C# 函数,该函数看起来很像您的 Java 代码,并且使用 Azure C# 库按预期工作(尽管我必须手动将程序集添加到 Visual Studio)。这让我觉得我遇到的问题其实是由于我的Maven环境的一些特质,我对Maven不太了解。我想使用 Java 函数,因为我有其他不想转换为 C# 的 Java 代码。所以如果你成功了,请告诉我。
    • @JackCopper 很抱歉这么晚才回复你,请给我一些时间来更新我的答案。谢谢。
    • @JackCopper 请查看我的更新答案。我遇到了同样的问题并想通了。
    • 感谢您的努力。我已经走神了,但今天会尝试实施您的解决方案。
    【解决方案2】:

    您能否分享有关您正在使用的方法和类型的任何详细信息?要进行输出绑定,您需要使用带有正确注释的 OutputBinding&lt;T&gt; 类。这是我刚刚测试的与您提到的类似的示例:

    @FunctionName("hello")
    public String hello(
            @HttpTrigger(name = "req", methods = {
                    "post" }, authLevel = AuthorizationLevel.ANONYMOUS) String req,
            ExecutionContext context, @BlobOutput(name = "blob", connection = "StorageAccount", path = "test/foo.txt")OutputBinding<String> blob)
            {
        blob.setValue("hello world");
        return String.format("Hello, %s!", req);
    }
    

    注意@BlobOutput 属性和OutputBinding 类型(可以是Stringbyte [],但我相信如果使用byte [],您还需要在@BlobAttribute 上将dataType 设置为“二进制”。

    让我知道这是否有效

    【讨论】:

    • 用例是:请求头中有一个容器ID和一个具体的文件名; blob 是传入的任何容器层次结构中固定位置的任意文件(文本);在函数中,我需要读取几行,然后将元数据添加到 blob。您的回答指出我要查看其他注释(例如,我认为需要使用流),但我仍在努力解决从请求标头获取参数到 blob 名称和所需连接参数的基础知识。
    猜你喜欢
    • 2018-05-07
    • 2021-01-04
    • 1970-01-01
    • 2019-08-26
    • 2020-09-19
    • 1970-01-01
    • 2020-04-03
    • 2021-10-08
    • 2021-11-08
    相关资源
    最近更新 更多