나는이 @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();
}
}
답변
할 수있는 것은 @Autowired
setter 메서드이며 새 정적 필드를 설정하도록하는 것입니다.
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();
}