【问题标题】:Java Spring - how to inject @Value to a data object?Java Spring - 如何将@Value 注入数据对象?
【发布时间】:2016-03-28 06:43:20
【问题描述】:

我有一个需要了解 Spring 配置文件的数据对象(仅带有 getters\setter),即

@Value("${spring.profiles.active}")
private String profile;

我在其中一个“设置”方法中添加了一个逻辑来检查配置文件,即

public void setItem(Item msg) {
    if (environmentProperties.isDevMode()) {
        this.msg= msg;
    }
}

因为这个类经常在外部编组\unmarhsalled,所以,当然@Value 没有被填充 - 因为我没有使用spring Autowire来创建类实例......我尝试将类定义为组件,并自动连接到保存配置文件 @Value 的外部类 - 但它不起作用 我使用 spring 3.2 - 没有 XML 定义。

有什么建议吗?

顺便说一句。 数据对象通常包装在异常类中 - 所以当它创建时,数据对象也应该知道配置文件......

谢谢!

已编辑:

  • 使用 ApplicationContextAware 不起作用 - 我得到 null 'setApplicationContext' 方法从未被调用。
  • 尝试直接获取上下文也不起作用 - 使用以下命令时获取 null: 'ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();'

固定: 我最终找到了一个如何从外部类静态访问上下文的示例:

@Configuration
public class ApplicationContextContainer implements ApplicationContextAware {

    private static ApplicationContext CONTEXT;

    /**
     * This method is called from within the ApplicationContext once it is
     * done starting up, it will stick a reference to itself into this bean.
     *
     * @param context a reference to the ApplicationContext.
     */
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        CONTEXT = context;
    }

    /**
     * This is about the same as context.getBean("beanName"), except it has its
     * own static handle to the Spring context, so calling this method statically
     * will give access to the beans by name in the Spring application context.
     * As in the context.getBean("beanName") call, the caller must cast to the
     * appropriate target class. If the bean does not exist, then a Runtime error
     * will be thrown.
     *
     * @param beanName the name of the bean to get.
     * @return an Object reference to the named bean.
     */
    public static Object getBean(String beanName) {
        return CONTEXT.getBean(beanName);
    }

【问题讨论】:

  • 你试过@DependsOn('yourPropertiesBeanName')吗?

标签: java spring inject


【解决方案1】:

如果我理解正确,您想注入不是由 Spring 管理的对象,而是由内部调用 new 并返回对象的其他代码创建的,例如一个序列化框架。

要注入非托管对象,您需要配置加载时或编译时编织。启动 VM 时,加载时编织需要代理参数和库,某些容器可能会为您执行此操作。

编译时编织需要使用 AspectJ 编译器。

您将在下面找到一个使用 Maven 和 Spring-Boot 的完整示例:

例如运行它:

mvn spring-boot:run -Drun.arguments="--spring.profiles.active=dev"

DemoApplication.java:

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {
    @EnableSpringConfigured
    @ComponentScan("com.example")
    public static class AppConfiguration {
        @Value("${spring.profiles.active}")
        String profile;

        @Bean
        public String profile() {
            return profile;
        }
    }

    @Configurable
    public static class SomePojo {
        @Autowired
        private String profile;

        public void print() {
            System.out.println(this + "\t" + profile);
        }
    }

    @Component
    public static class Runner {
        public void run() {
            new SomePojo().print();
            new SomePojo().print();
        }
    }

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

}

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.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.8</version>
                <configuration>
                    <complianceLevel>1.8</complianceLevel>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <id>compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

【讨论】:

    【解决方案2】:

    根据您的描述,您正在尝试将该属性注入 POJO,该 POJO 用于编组。使用这种结构,您可能会寻找基于静态/任何其他复杂解决方案的不同解决方法。

    我建议将用作 POJO 的 bean 与依赖于属性值的逻辑分开。您可以将该逻辑提取到 BeanService(可以放置到 Spring 上下文中)并在该级别上处理它,以便您分离 Service 和 Data 层之间的责任。

    【讨论】:

      【解决方案3】:

      你做错了。您的代码不需要知道配置文件。在您的示例中,创建一个 Message 接口和该接口的许多 bean 实现,每个配置文件一个,每个配置文件包含该配置文件的适当消息,并将每个分配给一个配置文件,以便为该配置文件实例化 bean,并将实例注入需要消息的类中。

      所以,

      public interface Message { String getMessage(); }
      
      @Profile("dev") @Component
      public class DevMessage implements Message { 
        public String getMessage() { return "this is the dev message"; }
      }
      
      @Profile("prod") @Component
      public class ProdMessage implements Message {
        public String getMessage() { return "this is the production message"; }
      }
      

      如果您更喜欢在 @Configuration 类中描述您的 bean,您可以使用 @Profile 标记整个配置,并拥有多个配置。

      如果你将 Message 实例注入到一个类中,你可以在它上面调用 getMessage()。该配置文件将确保您拥有适合您的环境的实施。

      编辑: 我刚刚重读了您的问题,并意识到我错了。您将实体对象存储在应用程序之外并通过一些代码/框架进行实例化。这些不是弹簧组件,因此不能使用弹簧方法进行依赖注入。在这种情况下,不要为它们使用弹簧——它不起作用,不必起作用,也不应该起作用。如果你没有通过spring实例化对象,那么它应该与spring无关。我不知道你的问题领域,但自从它发明以来我就一直在使用它,而且从来没有这样做过。

      【讨论】:

        猜你喜欢
        • 2013-01-15
        • 1970-01-01
        • 2019-05-28
        • 1970-01-01
        • 2015-08-21
        • 2015-10-25
        • 2018-08-18
        • 2022-06-12
        相关资源
        最近更新 更多