【问题标题】:How to make spring inject value into a static field如何使弹簧将值注入静态字段
【发布时间】:2012-07-04 16:18:25
【问题描述】:

我知道这可能看起来像以前提出的问题,但我在这里面临不同的问题。

我有一个只有静态方法的实用程序类。我没有,我也不会从中获取实例。

public class Utils{
    private static Properties dataBaseAttr;
    public static void methodA(){

    }

    public static void methodB(){

    }
}

现在我需要 Spring 用数据库属性 Properties.Spring 配置填充 dataBaseAttr:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">

<util:properties id="dataBaseAttr"
        location="file:#{classPathVariable.path}/dataBaseAttr.properties" />
</beans>

我已经在其他 bean 中完成了它,但是这个类(Utils)中的问题不是 bean,如果我把它变成一个 bean,我仍然无法使用该变量,因为该类不会被实例化并且变量总是等于 null。

【问题讨论】:

    标签: java spring configuration app-config


    【解决方案1】:

    你有两种可能:

    1. 静态属性/字段的非静态设置器;
    2. 使用org.springframework.beans.factory.config.MethodInvokingFactoryBean 调用静态设置器。

    在第一个选项中,您有一个带有常规 setter 的 bean,但您设置的是静态属性/字段,而不是设置实例属性。

    public void setTheProperty(Object value) {
        foo.bar.Class.STATIC_VALUE = value;
    }
    

    但为了做到这一点,你需要一个 bean 的实例来公开这个 setter(它更像是一个解决方法)。

    在第二种情况下,将按如下方式完成:

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
        <property name="arguments">
            <list>
                <ref bean="theProperty"/>
            </list>
       </property>
    </bean>
    

    在您的情况下,您将在 Utils 类上添加一个新的设置器:

    public static setDataBaseAttr(Properties p)
    

    在您的上下文中,您将使用上面举例说明的方法对其进行配置,或多或少类似于:

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="foo.bar.Utils.setDataBaseAttr"/>
        <property name="arguments">
            <list>
                <ref bean="dataBaseAttr"/>
            </list>
       </property>
    </bean>
    

    【讨论】:

    • 非常感谢,你真的拯救了我的一天。
    • 我没有尝试第一种解决方案,因为我不太了解它。我尝试了第二种解决方案,效果很好。
    • 肯定更喜欢这些选择中的第二个而不是第一个。每次创建实例时设置静态字段是一种非常奇怪的模式。
    • 你也可以像这样发送一个简单的属性:
    • staticMethodMethodInvokingFactoryBean 的一个属性,并且配置了完全限定的静态方法名称,wish 将使用提供给属性argument 的参数调用。
    【解决方案2】:

    我有一个类似的要求:我需要将 Spring 管理的存储库 bean 注入我的 Person 实体类(“实体”,如“具有身份的东西”,例如 JPA 实体)。一个Person 实例有朋友,为了让这个Person 实例返回它的朋友,它应该委托给它的存储库并在那里查询朋友。

    @Entity
    public class Person {
        private static PersonRepository personRepository;
    
        @Id
        @GeneratedValue
        private long id;
    
        public static void setPersonRepository(PersonRepository personRepository){
            this.personRepository = personRepository;
        }
    
        public Set<Person> getFriends(){
            return personRepository.getFriends(id);
        }
    
        ...
    }
    

    .

    @Repository
    public class PersonRepository {
    
        public Person get Person(long id) {
            // do database-related stuff
        }
    
        public Set<Person> getFriends(long id) {
            // do database-related stuff
        }
    
        ...
    }
    

    那么我是如何将 PersonRepository 单例注入到 Person 类的静态字段中的呢?

    我创建了一个@Configuration,它会在Spring ApplicationContext 构建时获取。这个@Configuration 被注入了所有我需要作为静态字段注入其他类的bean。然后使用@PostConstruct 注释,我捕获了一个钩子来执行所有静态字段注入逻辑。

    @Configuration
    public class StaticFieldInjectionConfiguration {
    
        @Inject
        private PersonRepository personRepository;
    
        @PostConstruct
        private void init() {
            Person.setPersonRepository(personRepository);
        }
    }
    

    【讨论】:

    • 你怎么可能通过静态方法访问它?我根本不相信这是可能的!不应该是 Person.personRepository = personRepository 吗?
    • @JonasGeiregat 它是可能的,因为该方法是静态的并且它正在访问静态变量
    • 我想知道有人如何在静态上下文中通过“this”引用静态变量?
    • 它可以工作,但这是不好的做法,就像你使用类名而不是这个一样。 Eclipes 会用警告标记它。
    • 您可以通过构造函数注入来完成此操作,然后不需要该字段或 postconstruct 方法
    【解决方案3】:

    由于这些答案很旧,我找到了这个替代方案。它非常干净,只使用 java 注释:

    要修复它,请创建一个“非静态设置器”来为静态变量分配注入值。例如:

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class GlobalValue {
    
    public static String DATABASE;
    
    @Value("${mongodb.db}")
    public void setDatabase(String db) {
        DATABASE = db;
    }
    }
    

    https://www.mkyong.com/spring/spring-inject-a-value-into-static-variables/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 2018-12-09
      相关资源
      最近更新 更多