[java] @Autowired 및 정적 메서드

나는이 @Autowired정적 메서드 내에서 사용하는 서비스입니다. 나는 이것이 틀렸다는 것을 알고 있지만 많은 작업이 필요하기 때문에 현재 디자인을 변경할 수 없으므로 간단한 해킹이 필요합니다. randomMethod()비 정적으로 변경할 수 없으며이 자동 연결 빈을 사용해야합니다. 그 방법에 대한 단서가 있습니까?

@Service
public class Foo {
    public int doStuff() {
        return 1;
    }
}

public class Boo {
    @Autowired
    Foo foo;

    public static void randomMethod() {
         foo.doStuff();
    }
}



답변

솔루션 중 하나에 따라이를 수행 할 수 있습니다.

@Autowired 생성자 사용

이 접근 방식은 생성자 매개 변수로 일부 빈이 필요한 빈을 생성합니다. 생성자 코드 내에서 생성자 실행을위한 매개 변수로 얻은 값으로 정적 필드를 설정합니다. 견본:

@Component
public class Boo {

    private static Foo foo;

    @Autowired
    public Boo(Foo foo) {
        Boo.foo = foo;
    }

    public static void randomMethod() {
         foo.doStuff();
    }
}

@PostConstruct를 사용하여 값을 정적 필드에 전달

여기서 아이디어는 bean이 spring에 의해 구성된 후 정적 필드에 bean을 넘겨주는 것입니다.

@Component
public class Boo {

    private static Foo foo;
    @Autowired
    private Foo tFoo;

    @PostConstruct
    public void init() {
        Boo.foo = tFoo;
    }

    public static void randomMethod() {
         foo.doStuff();
    }
}


답변

정적 애플리케이션 컨텍스트 접근 자 접근 방식을 통해이 문제를 해결해야합니다.

@Component
public class StaticContextAccessor {

    private static StaticContextAccessor instance;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.applicationContext.getBean(clazz);
    }

}

그런 다음 정적 방식으로 Bean 인스턴스에 액세스 할 수 있습니다.

public class Boo {

    public static void randomMethod() {
         StaticContextAccessor.getBean(Foo.class).doStuff();
    }

}


답변

할 수있는 것은 @Autowiredsetter 메서드이며 새 정적 필드를 설정하도록하는 것입니다.

public class Boo {
    @Autowired
    Foo foo;

    static Foo staticFoo;

    @Autowired
    public void setStaticFoo(Foo foo) {
        Boo.staticFoo = foo;
    }

    public static void randomMethod() {
         staticFoo.doStuff();
    }
}

빈이 처리되면 Spring은 Foo인스턴스 필드에 구현 인스턴스를 주입 합니다 foo. 그런 다음 정적 필드를 설정하는 데 사용되는 인수 목록에 동일한 Foo인스턴스를 삽입합니다 setStaticFoo().

이것은 끔찍한 해결 방법이며 randomMethod()Spring이 인스턴스를 처리하기 전에 사용하려고하면 실패합니다 Boo.


답변

짜증나지만 ApplicationContextAware인터페이스 를 사용하여 빈을 얻을 수 있습니다 . 다음과 같은 것 :

public class Boo implements ApplicationContextAware {

    private static ApplicationContext appContext;

    @Autowired
    Foo foo;

    public static void randomMethod() {
         Foo fooInstance = appContext.getBean(Foo.class);
         fooInstance.doStuff();
    }

    @Override
    public void setApplicationContext(ApplicationContext appContext) {
        Boo.appContext = appContext;
    }
}


답변

이것은 정적 getBean 메소드에서 액세스 할 때 Spring 컨텍스트가 초기화되지 않을 가능성을 해결하기 위해 @Pavel의 답변을 기반으로합니다 .

@Component
public class Spring {
  private static final Logger LOG = LoggerFactory.getLogger (Spring.class);

  private static Spring spring;

  @Autowired
  private ApplicationContext context;

  @PostConstruct
  public void registerInstance () {
    spring = this;
  }

  private Spring (ApplicationContext context) {
    this.context = context;
  }

  private static synchronized void initContext () {
    if (spring == null) {
      LOG.info ("Initializing Spring Context...");
      ApplicationContext context = new AnnotationConfigApplicationContext (io.zeniq.spring.BaseConfig.class);
      spring = new Spring (context);
    }
  }

  public static <T> T getBean(String name, Class<T> className) throws BeansException {
    initContext();
    return spring.context.getBean(name, className);
  }

  public static <T> T getBean(Class<T> className) throws BeansException {
    initContext();
    return spring.context.getBean(className);
  }

  public static AutowireCapableBeanFactory getBeanFactory() throws IllegalStateException {
    initContext();
    return spring.context.getAutowireCapableBeanFactory ();
  }
}

여기서 중요한 부분은 initContext방법입니다. 컨텍스트가 항상 초기화되도록합니다. 그러나 initContext동기화되면 코드에서 경합 지점이 될 것입니다. 애플리케이션이 과도하게 병렬화 된 경우 (예 : 트래픽이 많은 사이트의 백엔드) 이것은 좋은 솔루션이 아닐 수 있습니다.


답변

AppContext를 사용하십시오. 컨텍스트 파일에 Bean을 작성했는지 확인하십시오.

private final static Foo foo = AppContext.getApplicationContext().getBean(Foo.class);

public static void randomMethod() {
     foo.doStuff();
}


답변