Можете ли вы использовать @Autowired со статическими полями?

Есть ли способ использовать @Autowired со статическими полями. Если нет, есть ли другие способы сделать это?

13 ответов

Решение

Короче нет. Вы не можете автоматически связывать или вручную связывать статические поля в Spring. Вы должны написать свою собственную логику, чтобы сделать это.

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

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

@Autowired может использоваться с сеттерами, чтобы вы могли иметь сеттер, модифицирующий статическое поле.

Только одно последнее предложение... НЕ

Инициируйте свой автопроводной компонент в методе @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();
   }
}

Создайте bean-компонент, который вы можете автоматически связать, который будет инициализировать статическую переменную как побочный эффект.

Хотел добавить к ответам, что статическое поле (или константа) автоматического подключения будет игнорироваться, но также не вызовет никаких ошибок:

@Autowired
private static String staticField = "staticValue";

Вы можете достичь этого с помощью нотации XML и MethodInvokingFactoryBean, Для примера посмотрите здесь.

private static StaticBean staticBean;

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

Вы должны стремиться использовать пружинный впрыск, где это возможно, так как это рекомендуемый подход, но это не всегда возможно, поскольку я уверен, что вы можете себе представить, что не все можно извлечь из контейнера с пружиной или вы, возможно, имеете дело с устаревшими системами.

Тестирование заметок также может быть более сложным при таком подходе.

Вы можете использовать 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);

Я использую частный статический внутренний компонент: FieldSetter для ввода статического поля: MyBean, наконец, SelfDestroyBean поможет мне удалить избыточный компонент FiledSetter .

      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);
        }
    }
}

Отказ от ответственности Это ни в коем случае не является стандартом, и вполне может быть лучший весенний способ сделать это. Ни один из приведенных выше ответов не решает проблемы подключения общедоступного статического поля.

Я хотел добиться трех вещей.

  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 не вызывает ваши аспекты при вызове функции. Сделал это проще, но я разработал логику, прежде чем понять это.

Как правило, установка статического поля по экземпляру объекта - плохая практика.

чтобы избежать дополнительных проблем, вы можете добавить synchronized определение, и установить его, только если приватный статический логгер;

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

:

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

Решение 1. Использование конструктора @AutowiredДля статического поля

      @Component
public class MyClass {

    private static MyService service;

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

Решение 2. Использование @PostConstructчтобы установить значение для статического поля

      @Component
public class MyClass {

    private static MyService service;

    @Autowired
    private MyService srv;

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

Подробнее см. здесь

Другие вопросы по тегам