你能在静态字段中使用@Autowired 吗?

是否有一些方法可以将 @Autowired用于静态字段。如果没有,是否有其他方法可以做到这一点?

207401 次浏览

简而言之,没有。不能在 Spring 中自动连接或手动连接静态字段。要做到这一点,你必须写出自己的逻辑。

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

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

最后一个建议... 不要

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

private static StaticBean staticBean;


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

您应该以使用 在可能的情况下进行弹簧注射,因为这是推荐的方法为目标,但这并不总是可能的,因为我相信您可以想象到,并非所有东西都可以从弹簧容器中取出,或者您可能需要处理遗留系统。

使用这种方法进行注释测试可能会更加困难。

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


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

在@PostConstruction 方法中初始化您的自动连接组件

@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();
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

可以使用 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. 使用弹簧“ Autowire”(我使用@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 开头的方法,如果调用这些方法,将抛出一个错误。

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

当 Spring 调用一个函数时,它不会调用你的方面。让事情变得更简单,更糟糕的是,在弄清楚之前,我已经搞清楚了逻辑。

要添加的答案,自动布线静态字段(或常量)将被忽略,但也不会创建任何错误:

@Autowired
private static String staticField = "staticValue";

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

为了避免可选的问题,可以添加 synchronized定义,并设置它只有当私人静态日志记录器;

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

:

解决方案1: 对静态字段使用构造函数 @Autowired

@Component
public class MyClass {


private static MyService service;


@Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}

解决方案2: 使用 @PostConstruct将值设置为 StaticField

@Component
public class MyClass {


private static MyService service;


@Autowired
private MyService srv;


@PostConstruct
public void init() {
this.service= srv;
}
}

详情请参阅此处

我使用私有静态内部组件: 田野调查员,注入静态字段: 我的豆子,最后 自我毁灭豆将帮助我删除冗余的 FiledSetter bean

public final class MyClass {
private static MyBean myBean;


@Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
    

@SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
@Autowired
private ApplicationContext context;


@PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());


final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}