2017-10-20 174 views
0

我有一個http觸發azure函數(用Java編寫),我想訪問Blob存儲。代碼在maven下編譯,但是當我在本地運行並從CURL發送帖子時,運行時由於缺少com.microsoft.azure.storage.CloudStorageAccount而導致ClassNotFound異常而崩潰。 azure-storage(版本6.0.0)在POM文件中列爲依賴項。相關的.jar文件應該在哪裏才能被函數看到?我如何使用Java中的azure函數使用blob存儲

任何有關Java天藍色功能的見解將不勝感激。

回答

0

根據您的需求,我建議你跟隨這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對不起,這麼晚回覆你,請給我一些時間來更新我的答案。謝謝。 –

0

你能分享你正在使用的方法和類型的任何細節嗎?要執行輸出綁定,您需要使用帶有正確註釋的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名稱和連接參數。 –

相關問題