[SPRING] Spring에서 Lifecycle 인터페이스는 어떻게 작동합니까? "최상위 싱글 톤 빈"이란 무엇입니까?
SPRINGSpring에서 Lifecycle 인터페이스는 어떻게 작동합니까? "최상위 싱글 톤 빈"이란 무엇입니까?
Spring javadoc에서 "Lifecycle 인터페이스는 최상위 레벨 싱글 톤에서만 지원됩니다."라고 말합니다. 여기에 URL
My LifecycleBeanTest.xml은 bean을 다음과 같이 설명합니다.
<beans ...>
<bean id="lifecycle" class="tests.LifecycleBean"/>
</beans>
그래서 그것은 "topish"와 "singletonish"정도로 보인다.
무슨 뜻이에요? 스프링이 라이프 사이클을 구현하는 빈에 대해 어떻게 알게하고 그걸로 무엇을 할 수 있습니까?
Spring의 주요 메소드가 다음과 같다고 가정 해 보겠습니다.
public static void main(String[] args) {
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").close();
}
따라서 컨텍스트를 인스턴스화 한 다음 즉시 컨텍스트를 닫습니다.
내 구성에 일부 bean을 만들면 응용 프로그램이 작동 할 때까지 close () 실행이 지연 될 수 있습니까? 그래서 메인 메소드 스레드는 애플리케이션 종료를 기다린다.
예를 들어, 다음 bean은 내가 생각한 방식으로 작동하지 않습니다. start ()가 아니라 stop ()이 호출됩니다.
package tests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;
public class LifecycleBean implements Lifecycle {
private static final Logger log = LoggerFactory.getLogger(LifecycleBean.class);
private final Thread thread = new Thread("Lifecycle") {
{
setDaemon(false);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Abnormal thread termination", e);
}
});
}
public void run() {
for(int i=0; i<10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
};
};
@Override
public void start() {
log.info("Starting bean");
thread.start();
}
@Override
public void stop() {
log.info("Stopping bean");
thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
@Override
public boolean isRunning() {
return thread.isAlive();
}
}
업데이트 1
나는 코드에서 콩을 기다릴 수 있다는 것을 안다. Spring 자체에 연결하는 것은 흥미 롭습니다.
해결법
-
==============================
1.라이프 사이클 대신 SmartLifecycle을 사용해야합니다. 라이프 사이클이 작동 할 것으로 예상 할 때 전임자 만 작동합니다. isRunning () 구현에서 true를 반환해야합니다.
라이프 사이클 대신 SmartLifecycle을 사용해야합니다. 라이프 사이클이 작동 할 것으로 예상 할 때 전임자 만 작동합니다. isRunning () 구현에서 true를 반환해야합니다.
필자는 비동기 작업을 위해 SmartLifecycle을 사용했습니다. 나는 그것이 당신을 위해 일할 것이라고 생각하지만 동시에 ContextStoppedEvent와 같은 ApplicationListener와 이벤트를 살펴볼 것입니다.
-
==============================
2.AbstractApplicationContext.doClose () 메소드를 검사하고 Spring 개발자가 애플리케이션 컨텍스트 닫기를 중단하지 않았는지 확인할 수있다.
AbstractApplicationContext.doClose () 메소드를 검사하고 Spring 개발자가 애플리케이션 컨텍스트 닫기를 중단하지 않았는지 확인할 수있다.
protected void doClose() { boolean actuallyClose; synchronized (this.activeMonitor) { actuallyClose = this.active && !this.closed; this.closed = true; } if (actuallyClose) { if (logger.isInfoEnabled()) { logger.info("Closing " + this); } try { // Publish shutdown event. publishEvent(new ContextClosedEvent(this)); } catch (Throwable ex) { logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex); } // Stop all Lifecycle beans, to avoid delays during individual destruction. try { getLifecycleProcessor().onClose(); } catch (Throwable ex) { logger.warn("Exception thrown from LifecycleProcessor on context close", ex); } // Destroy all cached singletons in the context's BeanFactory. destroyBeans(); // Close the state of this context itself. closeBeanFactory(); // Let subclasses do some final clean-up if they wish... onClose(); synchronized (this.activeMonitor) { this.active = false; } } }
따라서 응용 프로그램 컨텍스트가 닫히는 것을 막을 수는 없습니다.
Spring 테스트 컨텍스트 프레임 워크를 JUnit과 함께 사용하는 경우,이를 사용하여 Lifecycle을 구현하는 서비스를 테스트 할 수 있다고 생각합니다. 내부 Spring 테스트 중 하나에서 기술을 사용했습니다.
약간 수정 된 LifecycleBean (waitForTermination () 메소드를 추가했습니다) :
public class LifecycleBean implements Lifecycle { private static final Logger log = LoggerFactory .getLogger(LifecycleBean.class); private final Thread thread = new Thread("Lifecycle") { { setDaemon(false); setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { log.error("Abnormal thread termination", e); } }); } public void run() { for (int i = 0; i < 10 && !isInterrupted(); ++i) { log.info("Hearbeat {}", i); try { sleep(1000); } catch (InterruptedException e) { return; } } }; }; @Override public void start() { log.info("Starting bean"); thread.start(); } @Override public void stop() { log.info("Stopping bean"); thread.interrupt(); waitForTermination(); } @Override public boolean isRunning() { return thread.isAlive(); } public void waitForTermination() { try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }
테스트 클래스 :
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:Test-context.xml") public class LifecycleBeanTest { @Autowired LifecycleBean bean; Lifecycle appContextLifeCycle; @Autowired public void setLifeCycle(ApplicationContext context){ this.appContextLifeCycle = (Lifecycle)context; } @Test public void testLifeCycle(){ //"start" application context appContextLifeCycle.start(); bean.waitForTermination(); } }
Test-context.xml 내용 :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="LifecycleBean"/> </beans>
추신 컨텍스트를 시작하고 중지하는 것은 동일한 응용 프로그램 컨텍스트에서 여러 번 할 수있는 일이 아니므로 최상의 결과를 얻으려면 테스트 메서드에 @DirtiesContextannotation을 넣어야 할 수도 있습니다.
DefaultLifecycleProcessor는 beanFactory.getBeanNamesForType (Lifecycle.class, false, false)를 사용합니다. 생명주기를 구현하는 빈 목록을 검색하는 방법 getBeanNamesForType부터 javadoc :
따라서이 메소드는 내부 bean을 나열하지 않습니다 (xml 구성 만 사용 가능할 때 중첩 호출 됨 - 중첩 된 bean xml 요소로 선언 됨).
문서에서 다음 예제를 고려하십시오.
<bean id="outer" class="..."> <!-- Instead of using a reference to target, just use an inner bean --> <property name="target"> <bean class="com.mycompany.PersonImpl"> <property name="name"><value>Tony</value></property> <property name="age"><value>51</value></property> </bean> </property> </bean>
Start () 및 Stop ()은 응용 프로그램 컨텍스트의 수명과 연결되지 않은 응용 프로그램 컨텍스트에 의해 전파되는 이벤트 일뿐입니다. 예를 들어 일부 서비스 빈과 함께 다운로드 관리자를 구현할 수 있습니다. 예를 들어 사용자가 "일시 중지" 당신은 "stop"이벤트를 방송 할 것이고, 사용자가 "start"버튼을 눌렀을 때 "start"이벤트를 방송함으로써 처리를 재개 할 수있다. 적절한 순서로 이벤트를 전달하기 때문에 Spring을 사용할 수 있습니다.
-
==============================
3.라이프 사이클 인터페이스를 사용한 적이 없으며 어떻게 작동하는지 잘 모르겠습니다. 그러나이 콜백을 컨텍스트에서 호출하는 것만으로 start ()를 호출하는 것처럼 보입니다.
라이프 사이클 인터페이스를 사용한 적이 없으며 어떻게 작동하는지 잘 모르겠습니다. 그러나이 콜백을 컨텍스트에서 호출하는 것만으로 start ()를 호출하는 것처럼 보입니다.
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("..."); ctx.start();
그러나 일반적으로 @ PostConstruct / @ PreDestroy 주석을 사용하거나 InitializingBean 및 DisposableBean을 구현합니다.
public class LifecycleBean implements InitializingBean, DisposableBean { @Override public void afterPropertiesSet() { //... } @Override public void destroy() { //... } }
응용 프로그램 컨텍스트에서 close ()를 호출하지 않습니다. LifecycleBean에서 비 데몬 쓰레드를 생성하고 있기 때문에 JVM은 main이 종료 되더라도 실행 상태를 유지합니다.
해당 스레드를 중지하면 JVM이 있지만 응용 프로그램 컨텍스트를 제대로 닫지 않습니다. 기본적으로 비 데몬 (non-daemon) 스레드가 중지되어 전체 JVM이 종료됩니다. 해커가 아닌 백그라운드 스레드가 끝날 때 응용 프로그램 컨텍스트를 명시 적으로 닫습니다.
public class LifecycleBean implements ApplicationContextAware /* ... */ { private AbstractApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = (AbstractApplicationContext)applicationContext; } public void run() { for(int i=0; i<10 && !isInterrupted(); ++i) { log.info("Hearbeat {}", i); try { sleep(1000); } catch (InterruptedException e) { } } applicationContext.close(); } }
-
==============================
4.그래서, 마침내 나는 만약 내가 발견 :
그래서, 마침내 나는 만약 내가 발견 :
1) 내 bean을 라이프 사이클을 구현하는 것으로 정의하십시오.
2) 다음과 같이 stop () 메소드에서 지연을 도입하십시오.
@Override public void stop() { log.info("Stopping bean"); //thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } }
3) 코드 컨텍스트 생성은 다음과 같습니다.
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").stop();
그럼 내가 원하는 것을 얻는다.
컨텍스트 생성 코드는 모든 라이프 사이클 빈의 모든 중지가 실행될 때까지 종료되지 않습니다. 따라서이 코드는 JUnit 테스트에서 작동합니다.
-
==============================
5.SmartLifecycle 사용은 어떻습니까? 필요한 모든 기능을 제공하는 것처럼 보입니다.
SmartLifecycle 사용은 어떻습니까? 필요한 모든 기능을 제공하는 것처럼 보입니다.
메소드 public void stop (Runnable contextStopping) {}이 있습니다. 또한 원하는 시간에 contextStopping을 전달하여 앱 컨텍스트 닫기를 계속할 수 있습니다.
내 환경에서는 J-UNIT에서도 물론 SpringJUnit4ClassRunner를 사용하여 모든 작업을 수행 할 수 있습니다.
from https://stackoverflow.com/questions/13551408/how-does-lifecycle-interface-work-in-spring-what-are-top-level-singleton-beans by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring XML의 "classpath :"와 "classpath : /"의 차이점은 무엇입니까? (0) | 2019.03.19 |
---|---|
[SPRING] OAuth2 클라이언트 자격증 명 흐름 이해하기 (0) | 2019.03.19 |
[SPRING] Spring RestTemplate 사후 응답 (0) | 2019.03.19 |
[SPRING] BCryptPasswordEncoder는 동일한 입력에 대해 다른 암호를 생성합니다. (0) | 2019.03.19 |
[SPRING] 스프링 데이터 JPA - 주입이 실패합니다 - BeanCreationException : 필드를 자동 줄 바꿈 할 수 없습니다. (0) | 2019.03.19 |