Чи можете ви використовувати @Autowired зі статичними полями?


Відповіді:


122

Словом, ні. Не можна автоматично з'єднувати або вручну проводити статичні поля навесні. Для цього вам доведеться написати власну логіку.


3
Коли ви знайдете старий код, що робить це, це анти-шаблон. Присідайте, нахиліть голову і знайдіть кращий спосіб вирішити проблему. Ви будете раді, що зробили.
Йосип Похоть

2
ця відповідь також корисна для весни@AutoWired
Кевін Мередіт

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

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

1
будь-яка ідея, як я можу використовувати цей підхід при ініціалізації сховища?
kiedysktos

3
Мінус: немає гарантії, someThingяка була ініціалізована, якщо матиме доступ до неї статично: NewClass.staticMethodWhichUsesSomething();може кинути NPE, якщо вона буде використана перед ініціалізацією додатків
Neeraj

Чи можете ви уникнути попередження Instance methods should not write to "static" fields (squid:S2696)?
user7294900

@ user7294900: вимкніть це попередження лише для цього, дуже конкретного випадку.
izogfif

@izogfif все ще є проблемою, якщо я вибираю це рішення у широких випадках та класах
user7294900

67

@Autowired можна використовувати із сеттерами, щоб у вас міг бути сетер, що змінює статичне поле.

Лише одна остаточна пропозиція ... НЕ


54
Чому ти пропонуєш цього не робити?
Джон Лоруссо

3
Хммм .. моє відчуття, чому це не рекомендується, є, бо тоді статичний екземпляр у класі поза контролем весни. Після того, як вводиться в поле статичного є посиланнями для всіх екземплярів об'єктів відповідного (навколишній) класу. Але така поведінка може бути саме такою, що, як очікується, відбудеться, тому вона може розглядатися як помилка чи особливість ...
matthaeus

1
Так @matthaeus, саме та функція, яку я очікував, коли потребував доступу до org.springframework.core.env.El Environment:@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
користувач1767316

@JonLorusso та все тому, що коли завантажувач класів завантажує статичні значення, контекст Spring ще не завантажений. Таким чином, завантажувач класів не буде належним чином вводити статичний клас у боб і вийде з ладу. Відповідь надав Андреа Т
Джеріл Курувіла

14

Запустіть свій автоматичний компонент в методі @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

Ви також можете це зробити безпосередньо через конструктор.
gagarwa

5

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


4

Ви можете досягти цього, використовуючи позначення XML та MethodInvokingFactoryBean. Для прикладу дивіться тут .

private static StaticBean staticBean;

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

Ви повинні прагнути використовувати пружинну ін'єкцію, де це можливо, оскільки це рекомендований підхід але це не завжди можливо, оскільки я впевнений, що ви можете уявити, що не все можна витягнути з пружинного контейнера або, можливо, ви маєте справу зі застарілими системами.

Зверніть увагу, тестування також може бути складніше при цьому підході.


2

Хотіли додати у відповіді, що статичне поле (або постійне) автоматичного проводки буде ігноровано, але також не створить жодної помилки:

@Autowired
private static String staticField = "staticValue";

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

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, як запобігти викликам до сетера, оскільки ми не можемо його приховати.

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

Цей аспект буде обгортати всі методи, починаючи з остаточного, і призведе до помилки, якщо вони викликаються.

Я не вважаю, що це особливо корисно, але якщо ви неприйнятні і хочете тримати вас горох та моркву, це один із способів зробити це безпечно.

Важливо Spring не називає ваші аспекти, коли він викликає функцію. Це полегшило, до поганого я розробив логіку, перш ніж з'ясувати це.


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

2
Хоча цей код може вирішити питання, включаючи пояснення, як і чому це вирішує проблему, справді допоможе покращити якість вашої публікації та, ймовірно, призведе до збільшення кількості голосів. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, а не лише про людину, яка зараз задає питання. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення та вказати, які обмеження та припущення застосовуються.
подвійний звуковий сигнал

Я думаю, що ця відповідь може взагалі не потребувати пояснень.
Chaklader Asfak Arefe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.