정적 필드와 함께 @Autowired를 사용할 수 있습니까?


답변:


122

요컨대 스프링에서는 정적 필드를 자동 와이어 링하거나 수동으로 와이어 링 할 수 없습니다. 이를 위해서는 자신 만의 논리를 작성해야합니다.


3
이 작업을 수행하는 오래된 코드를 찾으면 안티 패턴입니다. 곁눈질, 머리 기울이기 및 문제를 해결하는 더 좋은 방법을 찾으십시오. 기뻐하실 겁니다.
Joseph Lust

2
답변 은 Spring 's에서도 유용합니다@AutoWired
Kevin Meredith

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 setter와 함께 사용하면 정적 필드를 수정하는 setter를 가질 수 있습니다.

그냥 하나 개의 최종 제안 ... NOT DO


54
왜 이렇게하지 말라고 권합니까?
Jon Lorusso

3
흠 .. 왜 권장되지 않는지에 대한 나의 생각은 클래스의 정적 인스턴스가 스프링의 제어를 넘어 서기 때문입니다. 일단 정적 필드가 주입 대응 (주변) 클래스의 객체의 모든 인스턴스에 대한 참조. 그러나,이 행동은 정확히 일어날 것으로 예상되는 것일 수 있으므로, 버그 또는 특징으로 보일 수 있습니다.
matthaeus

1
예 @ matthaeus, org.springframework.core.env.Environment에 액세스해야 할 때 예상했던 기능입니다.@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
user1767316

@JonLorusso and all 클래스 로더가 정적 값을로드 할 때 Spring 컨텍스트는 아직로드되지 않아도됩니다. 따라서 클래스 로더는 Bean에 정적 ​​클래스를 올바르게 주입하지 않으므로 실패합니다. 안드레아 T가 제공하는 답변
Jeril Kuruvila에게

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

정적 변수를 부작용으로 초기화하는 autowire가 가능한 bean을 작성하십시오.


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

우리는 setter에 대한 호출을 숨길 수 없으므로 어떻게 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로 시작하는 모든 메소드를 랩핑하고 호출되면 오류를 발생시킵니다.

나는 이것이 특히 유용하다고 생각하지 않지만, 당신이 ocd이고 당신이 완두콩과 당근을 분리 된 상태로 유지하고 싶다면 이것을 안전하게하는 한 가지 방법입니다.

중요한 Spring은 함수를 호출 할 때 당신의 측면을 호출하지 않습니다. 이것을 쉽게하고 나쁘게 만들었습니다. 나는 그것을 이해하기 전에 논리를 해결했습니다.


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

2
이 코드가 문제를 해결하는 방법과 이유에 대한 설명포함 하여 질문을 해결할 수는 있지만 게시물의 품질을 향상시키는 데 도움이되고 더 많은 투표를 할 수 있습니다. 지금 질문하는 사람 만이 아니라 앞으로 독자들에게 질문에 대답하고 있음을 기억하십시오. 제발 편집 설명을 추가하고 제한 및 가정이 적용 무엇의 표시를 제공하는 답변을.
더블

이 답변에는 전혀 설명이 필요하지 않을 수도 있습니다.
Chaklader Asfak Arefe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.