您可以将@Autowired与静态字段一起使用吗?


Answers:


122

简而言之,没有。您不能在Spring中自动连线或手动连线静态字段。为此,您必须编写自己的逻辑。


3
当您发现执行此操作的旧代码时,这是一种反模式。蹲下,歪头,找到解决问题的更好方法。您会很高兴的。
Joseph Lust

2
这个答案对春季@AutoWired
Kevin Meredith 2014年

116
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}

1
知道如何在初始化存储库时使用这种方法吗?
kiedysktos

3
缺点:someThing如果静态访问,则无法保证已初始化:NewClass.staticMethodWhichUsesSomething();如果在应用初始化之前使用,则可能会抛出NPE
Neeraj

您可以避免警告Instance methods should not write to "static" fields (squid:S2696)吗?
user7294900

@ user7294900:仅在非常特殊的情况下禁用此警告。
izogfif

如果我在广泛的案例和类中选择此解决方案,则@izogfif仍然是一个问题
user7294900

67

@Autowired 可以与设置器一起使用,因此可以让设置器修改静态字段。

最后一个建议... 不要


54
您为什么建议不这样做?
乔恩·洛鲁索

3
嗯..我之所以不推荐使用它,是因为类中的静态实例超出了spring的控制范围。注入静态字段后,便是对应(周围)类对象的所有实例引用。但是,此行为可能正是预期发生的情况,因此可能被视为错误或功能...
matthaeus13 13-4-13

1
是@matthaeus,这正是我在需要访问org.springframework.core.env.Environment时所期望的功能:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316

@JonLorusso以及其他所有内容因为在类加载器加载静态值时,尚无必要加载Spring上下文。因此,类加载器不会正确地将静态类注入Bean中,并且将失败。答案由Andrea T
杰里尔·库鲁维拉

14

在@PostConstruct方法中初始化自动装配的组件

@Component
public class TestClass {
   private static AutowiredTypeComponent component;

   @Autowired
   private AutowiredTypeComponent autowiredComponent;

   @PostConstruct
   private void init() {
      component = this.autowiredComponent;
   }

   public static void testMethod() {
      component.callTestMethod();
   }
}

您可以避免警告Instance methods should not write to "static" fields (squid:S2696)吗?
user7294900

您也可以直接通过构造函数执行此操作。
gagarwa

5

创建一个可以自动装配的bean,它将初始化静态变量作为副作用。


4

您可以使用XML表示法和来实现MethodInvokingFactoryBean。例如看这里

private static StaticBean staticBean;

public void setStaticBean(StaticBean staticBean) {
   StaticBean.staticBean = staticBean;
}

您应该尽可能地使用弹簧注入,因为这是推荐的方法,但是这种方法并非总是可行的,因为我敢肯定,您可以想象,不是所有东西都可以从弹簧容器中拉出,或者您可能正在使用旧系统。

使用此方法进行音符测试也可能更加困难。


1

您可以使用ApplicationContextAware

@Component
public class AppContext implements ApplicationContextAware{
    public static ApplicationContext applicationContext;

    public AppBeans(){
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

然后

static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);

1

想要添加到答案中,自动接线的静态字段(或常量)将被忽略,但也不会产生任何错误:

@Autowired
private static String staticField = "staticValue";

0

免责声明这绝不是标准,并且这样做的方式可能会更好。上述答案均未解决连接公共静态场的问题。

我想完成三件事。

  1. 使用spring进行“自动装配”(我使用@Value)
  2. 公开静态价值
  3. 防止修改

我的物件看起来像这样

private static String BRANCH = "testBranch";

@Value("${content.client.branch}")
public void finalSetBranch(String branch) {
    BRANCH = branch;
}

public static String BRANCH() {
    return BRANCH;
}

现在我们已经检查了1和2,因为我们无法隐藏它,所以我们如何防止呼叫设置器。

@Component
@Aspect
public class FinalAutowiredHelper {

@Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
    throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}

@Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}


public class ModifySudoFinalError extends Error {
    private String msg;

    public ModifySudoFinalError(String msg) {
        this.msg = msg;
    }

    @Override
    public String getMessage() {
        return "Attempted modification of a final property: " + msg;
    }
}

这方面将包装所有以final开头的方法,如果调用它们将引发错误。

我认为这不是特别有用,但是如果您是ocd,并且喜欢将豌豆和胡萝卜分开,则这是安全进行此操作的一种方法。

重要提示 Spring在调用函数时不会调用您的方面。使这变得更容易,更糟糕的是,我在弄清楚之前先弄清楚了逻辑。


-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

2
尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。
哔哔声,

我认为这个答案可能根本不需要任何解释。
Chaklader Asfak Arefe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.