在应用程序启动时将实例注册为“单例”bean

4
我正在尝试使用Spring Boot,构建ServiceImpl实例以在需要Service时进行解析。目前,我将实现注释为@Component,但这并不给我想要的构建实例的机会。 ServiceImpl应该使用包含磁盘上文件路径的字符串进行构建。我希望在应用程序的@SpringBootApplication类的主方法中执行此操作。
也许这只是因为我来自一个长期的.NET背景,我们通常会像这样设置IoC容器:
Service service = new Service("C:\\data.bin");
container.RegisterSingleton<IService>(service); // now whoever asks for a IService will receive this precise instance

这在Spring世界中有意义吗?
注:我很清楚GoF单例模式的定义(即防止其他人创建类的实例)- 我不是针对这个问题。

1
你是否事先知道这个属性?如果是,为什么不将其存储在属性中并直接将其自动装配到bean中呢? - dimitrisli
我没有考虑将它存储在属性中,这是一个很好的建议!实际上,您可以将其提升为答案 :) - Andrei Rînea
2个回答

6
在拥有@SpringBootApplication的同一文件中,进行以下操作:
@Bean
public IService service() {
    return new Service("C:\\data.bin");
}

Spring应该为您自动连接一切。默认情况下,它应该是单例 (http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-factory-scopes)。

编辑1:您还应该使用@Service注释您的Service实现,而不是@Component (请参见:Spring中@Component、@Repository和@Service注解之间有什么区别?)。

编辑2:您也不一定要将@Bean方法放在具有@SpringBootApplication注释的类中。您可以将其放在任何具有@Configuration注释的类中。


最终使用了这个版本 :) - Andrei Rînea

4

正如评论中所述,可以通过在配置文件中存储位置详细信息,然后在Spring Bean初始化时注入它们来实现此操作。

假设您的application.properties文件如下:

my.sample.config.A=somelocationA
my.sample.config.B=somelocationB
my.sample.config.C=somelocationC
my.sample.config.D.one=somelocationD1
my.sample.config.D.two=somelocationD2

以下是4种实现方法的演示:
1. 通过在Bean方法创建时直接注入属性:
@Bean
public A myBeanA(@Value("${my.sample.config.A}") String myprop) {
    System.out.println("from bean A with " + myprop);
    return new A(myprop);
}

2.通过在全局变量上注入属性,并在Bean方法创建中使用它:

@Value("${my.sample.config.B}")
private String mylocationB;
//..
@Bean
public B myBeanB() {
    System.out.println("from bean B with " + mylocationB);
    return new B(mylocationB);
}

3.通过将整个环境注入配置中,然后手动选择所需的属性:

@Autowired
private Environment env;
//..
    @Bean 
    public C myBeanC() {
    String locationC = env.getProperty("my.sample.config.C");
    System.out.println("from bean C with " + locationC);
    return new C(locationC);
}

4.这是Spring Boot的专属方法。您可以使用类型安全的配置属性,通过在您的bean上注释@ConfigurationProperties来定义前缀命名空间,从该点开始的所有参数都将自动映射到该bean中定义的属性!

@ConfigurationProperties(prefix = "my.sample.config.D")
@Component
class D {
    private String one;
    private String two;

    public String getOne() { return one; }

    public void setOne(String one) {
        System.out.println("from bean D with " + one);
        this.one = one;
    }
    public String getTwo() { return two; }

    public void setTwo(String two) {
        System.out.println("from bean D with " + two);
        this.two = two;
    }
}

以下是整个代码的单文件版本:


package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {

    @Autowired
    private Environment env;

    @Value("${my.sample.config.B}")
    private String mylocationB;

    @Bean
    public A myBeanA(@Value("${my.sample.config.A}") String myprop) {
        System.out.println("from bean A with " + myprop);
        return new A(myprop);
    }

    @Bean
    public B myBeanB() {
        System.out.println("from bean B with " + mylocationB);
        return new B(mylocationB);
    }

    @Bean
    public C myBeanC() {
        String locationC = env.getProperty("my.sample.config.C");
        System.out.println("from bean C with " + locationC);
        return new C(locationC);
    }

    @ConfigurationProperties(prefix = "my.sample.config.D")
    @Component
    class D {
        private String one;
        private String two;

        public String getOne() { return one; }

        public void setOne(String one) {
            System.out.println("from bean D with " + one);
            this.one = one;
        }
        public String getTwo() { return two; }

        public void setTwo(String two) {
            System.out.println("from bean D with " + two);
            this.two = two;
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    class A {
        private final String location;
        public A(String location) { this.location = location; }
    }

    class B {
        private final String location;
        public B(String location) { this.location = location; }
    }

    class C {
        private final String location;
        public C(String location) { this.location = location; }
    }

}

谢谢,回答很好。如果您能解释如何使用D类,那就更好了。 - Emdadul Sawon
@EmdadulSawon 谢谢 - 我已经添加了文档链接,您可以在其中找到有关它的所有详细信息。 - dimitrisli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接