简体   繁体   English

为什么我不能将字符串传递给 Spring 中的 @Service class 构造函数?

[英]Why can't I pass a String to a @Service class constructor in Spring?

I have a Spring Boot app that provides files to users via a web front-end.我有一个 Spring 引导应用程序,它通过 web 前端向用户提供文件。 Users can browse various file back-ends (dropbox, local filesystem etc) and then add that file to their library.用户可以浏览各种文件后端(保管箱、本地文件系统等),然后将该文件添加到他们的库中。 The class below concerns only part of the service layer that queries the Dropbox API.下面的 class 仅涉及查询 Dropbox API 的服务层的一部分。 The final version will have several other methods but for now, this all that has been implemented:最终版本将有其他几种方法,但目前,这一切都已实现:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.*;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

@Service
public class DbxService {

    private final String dropboxApiAccessToken;
    private final OkHttpClient httpClient;
    private final String dropboxApiAccessTokenFilePath;
    private final ObjectMapper jsonObjectMapper; //fasterxml.jackson.databind.ObjectMapper

    DbxService(String dropboxApiAccessTokenFilePath) throws IOException {
        this.dropboxApiAccessTokenFilePath = dropboxApiAccessTokenFilePath;
        this.httpClient = new OkHttpClient();
        this.jsonObjectMapper = new ObjectMapper();
        this.dropboxApiAccessToken = Files.readString(Path.of(dropboxApiAccessTokenFilePath));
    }

    public String listDropboxDirectory(String path) throws IOException {
        //jackson.databind.node.ObjectNode
        ObjectNode jsonPostRequestNode = jsonObjectMapper.createObjectNode();
        //need JSON string {"path": "[path]"} for Dropbox API Post request
        jsonPostRequestNode.put("path", path);

        //okhttp3 request
        Request dropboxApiRequest = new Request.Builder()
                .url("https://api.dropboxapi.com/2/files/list_folder")
                .post(RequestBody.create(jsonPostRequestNode.asText(), MediaType.parse("application/json")))
                .addHeader("Authorization", "Bearer " + this.dropboxApiAccessToken)
                .addHeader("Content-Type", "application/json")
                .build();
        Response dropboxApiResponse = this.httpClient.newCall(dropboxApiRequest).execute();
        return dropboxApiResponse.body().string();
    }
}

My class is thread-safe as it is immutable - there should not be a problem with it being a singleton (indeed, I very much want it to be a singleton).我的 class 是线程安全的,因为它是不可变的 - 作为 singleton 应该没有问题(实际上,我非常希望它是单例)。 It would be totally overkill for me to have some other back-end/data repository storing this path, however I do want it to be definable once - say in a configuration class - without having to hard-code the path string literal into a field.让其他一些后端/数据存储库存储此路径对我来说完全是矫枉过正,但是我确实希望它可以定义一次- 例如在配置 class 中 - 无需将路径字符串文字硬编码到字段中.

The above code-snippet results in the following error: "Could not autowire. No beans of 'String' type found.".上面的代码片段导致以下错误:“无法自动装配。找不到'String'类型的bean。”。 My own investigations suggest it is not possible to inject objects into Spring managed components that are not, in themselves, Spring beans.我自己的调查表明不可能将对象注入到 Spring 托管组件中,这些组件本身不是 Spring bean。

How can I refactor this snippet/service to avoid this error?如何重构此代码段/服务以避免此错误?

You might be able to inject a String if you actually register the instance as a been first (never tried).如果您实际上将实例注册为第一个(从未尝试过),您可能能够注入一个String Maybe you also need a @Qualifier -annotation, if there is more than one String bean.如果有多个 String bean,也许您还需要一个@Qualifier -annotation。

Usually, in Spring Boot the application.yml / application.properties is used for environment configuration.通常,在 Spring Boot 中application.yml / application.properties用于环境配置。 The values can either be mapped to a POJO which is annotated with @ConfigurationProperties .这些值可以映射到使用@ConfigurationProperties注释的 POJO。 This allows way you get type safe properties which can be injected in other beans/ services.这允许您获得可以注入其他 bean/服务的类型安全属性。 Or you can use the @Value -annotation to inject a single specific property in a bean/ service.或者您可以使用@Value -annotation 在 bean/ 服务中注入单个特定属性。

It turns out that it is not possible to inject objects that are not Spring Beans into a Spring @Service or @Component.事实证明,不可能将不是 Spring Bean 的对象注入到 Spring @Service 或 @Component 中。 In my particular case, I am trying to allow for the injection of a String representing the path to a file containing an API key into my @Service class constructor.在我的特殊情况下,我试图允许将表示包含 API 密钥的文件的路径的字符串注入到我的 @Service class 构造函数中。

I managed to get my code to work, as desired, by using Spring's @Value annotation.通过使用 Spring 的 @Value 注释,我设法让我的代码按照需要工作。 I created en entry in my application.properties file:我在 application.properties 文件中创建了条目:

DropboxService.AccessToken.FilePath="/foo/bar/credentialsFile" DropboxService.AccessToken.FilePath="/foo/bar/credentialsFile"

and changed my code to the following (note the @Value annotation before the class constructor method parameter):并将我的代码更改为以下内容(注意 class 构造函数方法参数之前的 @Value 注释):

package org.jdnet.audioBookPlayer.Utility;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

@Service
public class DbxService {

    private final String dropboxApiAccessToken;
    private final OkHttpClient httpClient;
    private final String dropboxApiAccessTokenFilePath;
    private final ObjectMapper jsonObjectMapper; //fasterxml.jackson.databind.ObjectMapper

    DbxService(@Value("${DropboxService.AccessToken.FilePath}") String dropboxApiAccessTokenFilePath) throws IOException {
        this.dropboxApiAccessTokenFilePath = dropboxApiAccessTokenFilePath;
        this.httpClient = new OkHttpClient();
        this.jsonObjectMapper = new ObjectMapper();
        this.dropboxApiAccessToken = Files.readString(Path.of(dropboxApiAccessTokenFilePath));
    }

    public String listDropboxDirectory(String path) throws IOException {
        //jackson.databind.node.ObjectNode
        ObjectNode jsonPostRequestNode = jsonObjectMapper.createObjectNode();
        //need JSON string {"path": "[path]"} for Dropbox API Post request
        jsonPostRequestNode.put("path", path);

        //okhttp3 request
        Request dropboxApiRequest = new Request.Builder()
                .url("https://api.dropboxapi.com/2/files/list_folder")
                .post(RequestBody.create(jsonPostRequestNode.asText(), MediaType.parse("application/json")))
                .addHeader("Authorization", "Bearer " + this.dropboxApiAccessToken)
                .addHeader("Content-Type", "application/json")
                .build();
        Response dropboxApiResponse = this.httpClient.newCall(dropboxApiRequest).execute();
        return dropboxApiResponse.body().string();
    }
}

A better answer would explain why I cannot simply use a @Bean definition in a configuration class as the only good reason I can see for Spring not being able to load a String in is that it cannot know which string to pass in when it tries to autowiring.一个更好的答案可以解释为什么我不能简单地在配置 class 中使用 @Bean 定义,这是我看到 Spring 无法加载字符串的唯一充分理由是它无法知道在尝试加载字符串时要传入哪个字符串自动装配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我们不能在Java构造函数中传递字符串 - why can't we pass string in java constructor 为什么我不能将服务 class 注入 Spring 批处理 JUnit 测试 class? - Why I can't inject a service class into a Spring Batch JUnit test class? 为什么不能在类的构造函数中调用静态方法? - Why can't I call a static method in the constructor of a class? 为什么我不能在类中声明字符串? - Why can't I declare a string in a class? 为什么我不能将这个 Spring 引导服务 class 注入 JUnit 测试 class? 预计至少有 1 个符合自动装配候选条件的 bean - Why I can't inject this Spring Boot service class into a JUnit test class? expected at least 1 bean which qualifies as autowire candidate 我可以将 class 的字段传递给构造函数或方法吗? - Can I pass a field of a class to a constructor or a method? 为什么可以将浮点数传递给Double的构造函数? - Why can I pass a float to the constructor of Double? 我可以在 Spring 中为 @Component 类创建一个构造函数吗 - Can I create a constructor for a @Component class in Spring 在春季启动中,为什么我没有将服务类的返回值返回给另一个服务类 - in spring boot, why i did`t get returned value of a service class to another service class 传递“HardCoded”构造函数Arg类 <T> 通过Spring Config来bean - pass “HardCoded” Constructor Arg Class<T> to bean via Spring Config
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM