我如何使用Java中的azure函数使用blob存储

问题描述:

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

任何有关Java天蓝色功能的见解将不胜感激。

根据您的需求,我建议你跟随这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=jaygong;" + 
        "AccountKey=bmrgAHzDrL8FsbQOJP0xnYYNXrNOmfSZyBdzedlFG/famIHK9gJB/UUQzWbQ6DB/dq7zPZ/YMrk3bMcO+1hjrA=="; 

    @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包。

enter image description here

使用命令mvn azure-functions:run到本地运行的蔚蓝功能。

enter image description here


更新答:

我跑我的蔚蓝功能和复制相同的异常如你所说。

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: 

经过一番研究,我发现,这是因为瓶子包装不dependent jar packages

所以,我加了如下配置的片断到我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文件。

enter image description here

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

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

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

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

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

enter image description here

此外,你可以参考这个github doc约蔚蓝function maven plugin更多详细配置信息。

希望它可以帮助你。

+0

我想你会发现,如果你真的执行你的函数(上面显示的只是表示函数被加载),它会崩溃,我遇到了同样的错误。使用CURL向其发送HTTP消息。如果它没有崩溃,那么请告诉我MS存储库在本地计算机上的位置。 –

+0

我很好奇,如果你能够使用CURL来运行你的功能。我能够在本地创建和运行一个C#函数,它看起来非常像Java代码,并且可以按照预期的方式使用Azure C#库(尽管我必须手动向Visual Studio中添加程序集)。这让我觉得我遇到的问题实际上是由于我的Maven环境的一些特质,并且我不太了解Maven。我想使用Java函数,因为我有其他不想转换为C#的Java代码。所以如果你成功了,请让我知道。 –

+0

@JackCopper对不起,这么晚回复你,请给我一些时间来更新我的答案。谢谢。 –

你能分享你正在使用的方法和类型的任何细节吗?要执行输出绑定,您需要使用带有正确注释的OutputBinding<T>类。这里我只是测试做类似你所提到的一个示例:

@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“二进制”。

让我知道是否可行

+0

用例是:容器ID和特定的文件名在请求头中; blob是传入的任何容器的层次结构中的固定位置中的任意文件(文本)在函数中我需要读几行然后添加元数据到blob。您的回答指向我查看其他注释(例如,我认为需要使用流),但我仍在努力从请求头获取参数到所需的blob名称和连接参数。 –