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

Posted

技术标签:

【中文标题】您可以将@Autowired 与静态字段一起使用吗?【英文标题】:Can you use @Autowired with static fields? 【发布时间】:2010-11-04 08:44:33 【问题描述】:

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

【问题讨论】:

***.com/questions/10938529/…相关 【参考方案1】:

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

【讨论】:

当你发现旧代码这样做时,这是一种反模式。眯着眼睛,歪着头,找到解决问题的更好方法。你会很高兴你做到了。 this answer 对 Spring 的 @AutoWired 也有帮助【参考方案2】:

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

【讨论】:

【参考方案3】:

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

最后一个建议...不要

【讨论】:

你为什么不建议这样做? 嗯..我对为什么不推荐它的感觉是,因为那时类中的静态实例超出了spring的控制范围。注入后,静态字段是相应(周围)类的所有对象实例的 引用。但是,这种行为可能正是预期会发生的,因此可能被视为错误或功能...... 是的@matthaeus,这正是我在需要访问 org.springframework.core.env.Environment 时所期望的功能:@Component public class SpringAppEnv public static Environment _env; @Autowired public void setEnv(Environment env) _env = env; @JonLorusso and all 因为当类加载器加载静态值时,还没有必要加载 Spring 上下文。所以类加载器不会正确地在 bean 中注入静态类并且会失败。 Andrea T 提供的答案【参考方案4】:

您可以使用 XML 表示法MethodInvokingFactoryBean 来实现这一点。例如看here。

private static StaticBean staticBean;

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

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

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

【讨论】:

【参考方案5】:
@Component("NewClass")
public class NewClass
    private static SomeThing someThing;

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

【讨论】:

知道如何在初始化存储库时使用这种方法吗? 缺点:不能保证 someThing 如果静态访问则已初始化:NewClass.staticMethodWhichUsesSomething(); 如果在应用程序初始化之前使用,可能会抛出 NPE 能避免Instance methods should not write to "static" fields (squid:S2696)的警告吗? @user7294900:仅针对这种非常特殊的情况禁用此警告。 @izogfif 仍然是一个问题,如果我在广泛的案例和类中选择此解决方案【参考方案6】:

在@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 我想这个警告告诉我们为什么这被认为是一种反模式。当实例方法写入静态变量时,静态变量成为类的所有对象共享的关键资源,从而在多线程环境中产生潜在问题。 它拯救了我的一天【参考方案7】:
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

【讨论】:

虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 我认为这个答案可能根本不需要任何解释。【参考方案8】:

你可以使用 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);

【讨论】:

【参考方案9】:

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

我想完成三件事。

    使用弹簧“自动装配”(我使用@Value) 公开一个公共静态值 防止修改

我的对象看起来像这样

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 在调用函数时不会调用你的切面。让这变得更容易了,糟糕的是我在弄清楚之前就弄清楚了逻辑。

【讨论】:

【参考方案10】:

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

@Autowired
private static String staticField = "staticValue";

【讨论】:

【参考方案11】:

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

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

@Autowired
public synchronized void setLogger(Logger logger)

    if (MyClass.logger == null)
    
        MyClass.logger = logger;
    

【讨论】:

以上是关于您可以将@Autowired 与静态字段一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以将全文搜索 (FTS) 与 LINQ 一起使用?

我应该使用静态字段并互锁在一起吗?

我们可以在 Java 中将两种字体样式组合在一起吗?

Spring @Autowired 和 @Qualifier [关闭]

Spring @Autowired 和 @Qualifier [关闭]

我们可以在抽象类中使用静态方法吗?