181

有什么方法可以@Autowired与静态字段一起使用。如果没有,还有其他方法可以做到这一点吗?

4

11 回答 11

146

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

于 2009-06-19T17:13:28.620 回答
142
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}
于 2011-05-13T11:33:07.977 回答
71

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

只有一个最后的建议......不要

于 2009-06-20T01:27:07.090 回答
25

在 @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();
   }
}
于 2017-12-26T10:38:01.117 回答
5

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

于 2009-06-20T01:21:49.787 回答
4

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

@Autowired
private static String staticField = "staticValue";
于 2019-10-24T08:15:07.387 回答
3

您可以使用XML 表示法MethodInvokingFactoryBean. 例如看这里

private static StaticBean staticBean;

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

您应该尽可能使用弹簧注入,因为这是推荐的方法,但这并不总是可行的,因为我相信您可以想象并非所有东西都可以从弹簧容器中提取出来,或者您可能会处理遗留系统。

使用这种方法进行笔记测试也可能更加困难。

于 2009-06-22T09:37:59.167 回答
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);
于 2019-06-14T06:52:03.443 回答
0

免责声明这绝不是标准的,很可能有更好的弹簧方式来做到这一点。以上答案都没有解决连接公共静态字段的问题。

我想完成三件事。

  1. 使用弹簧“自动装配”(我使用@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 现在我们如何防止调用 setter,因为我们无法隐藏它。

@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 开头的方法,如果它们被调用则抛出错误。

我不认为这特别有用,但如果你是强迫症并且喜欢把豌豆和胡萝卜分开,这是一种安全的方法。

重要Spring 在调用函数时不会调用你的切面。让这更容易,糟糕的是,我在弄清楚之前制定了逻辑。

于 2019-06-22T01:09:40.227 回答
0

通常,通过对象实例设置静态字段是一种不好的做法。

为避免可选问题,您可以添加synchronized定义,并仅在私有静态 Logger 记录器时设置它;

@Autowired
public synchronized void setLogger(Logger logger)
{
    if (MyClass.logger == null)
    {
        MyClass.logger = logger;
    }
}

于 2020-11-11T14:14:35.043 回答
-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
于 2019-03-26T11:19:11.233 回答