您可以将@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 与静态字段一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章
Spring @Autowired 和 @Qualifier [关闭]