애플리케이션 컨텍스트 초기화 이벤트에 후크를 추가하는 방법은 무엇입니까?
일반 Servlet의 경우 컨텍스트 리스너를 선언 할 수 있다고 생각 하지만 Spring MVC의 경우 Spring이 이것을 더 쉽게 만들 수 있습니까?
또한 컨텍스트 리스너를 정의한 다음 my servlet.xml
또는에 정의 된 Bean에 액세스해야하는 applicationContext.xml
경우 어떻게 액세스 할 수 있습니까?
Spring에는 처리 할 수있는 몇 가지 표준 이벤트가 있습니다.
이를 수행하려면 ApplicationListener
다음과 같이 인터페이스 를 구현하는 Bean을 작성하고 등록해야합니다 .
package test.pack.age;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationListenerBean implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
}
그런 다음이 Bean을 사용자 servlet.xml
또는 applicationContext.xml
파일에 등록 합니다.
<bean id="eventListenerBean" class="test.pack.age.ApplicationListenerBean" />
Spring은 애플리케이션 컨텍스트가 초기화 될 때이를 알립니다.
Spring 3 (이 버전을 사용하는 경우)에서 ApplicationListener
클래스는 제네릭 이며 관심있는 이벤트 유형을 선언 할 수 있으며 그에 따라 이벤트가 필터링됩니다. 다음과 같이 빈 코드를 약간 단순화 할 수 있습니다.
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
Spring 4.2부터 사용할 수 있습니다 @EventListener
( 문서 )
@Component
class MyClassWithEventListeners {
@EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
System.out.println("a context refreshed event happened");
}
}
주석 만들기
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterSpringLoadComplete {
}
수업 만들기
public class PostProxyInvokerContextListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
ConfigurableListableBeanFactory factory;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
try {
BeanDefinition definition = factory.getBeanDefinition(name);
String originalClassName = definition.getBeanClassName();
Class<?> originalClass = Class.forName(originalClassName);
Method[] methods = originalClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AfterSpringLoadComplete.class)){
Object bean = context.getBean(name);
Method currentMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
currentMethod.invoke(bean);
}
}
} catch (Exception ignored) {
}
}
}
}
@Component 주석 또는 xml로이 클래스를 등록합니다.
<bean class="ua.adeptius.PostProxyInvokerContextListener"/>
컨텍스트가 초기화 된 후 실행하려는 모든 메서드에서 다음과 같이 주석을 사용합니다.
@AfterSpringLoadComplete
public void init() {}
URL을 입력 할 때 단일 페이지 응용 프로그램을 사용하여 여러 데이터베이스의 데이터를 포함하는 HashMap (내 웹 페이지에서 사용)을 생성했습니다. 서버 시작 시간 동안 모든 것을로드하기 위해 다음 작업을 수행했습니다.
1- ContextListenerClass 생성
public class MyAppContextListener implements ServletContextListener
@Autowired
private MyDataProviderBean myDataProviderBean;
public MyDataProviderBean getMyDataProviderBean() {
return MyDataProviderBean;
}
public void setMyDataProviderBean(MyDataProviderBean MyDataProviderBean) {
this.myDataProviderBean = MyDataProviderBean;
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
}
@Override
public void contextInitialized(ServletContextEvent context) {
System.out.println("ServletContextListener started");
ServletContext sc = context.getServletContext();
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(sc);
MyDataProviderBean MyDataProviderBean = (MyDataProviderBean)springContext.getBean("myDataProviderBean");
Map<String, Object> myDataMap = MyDataProviderBean.getDataMap();
sc.setAttribute("myMap", myDataMap);
}
2- web.xml에 아래 항목 추가
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.context.listener.MyAppContextListener</listener-class>
</listener>
3- In my Controller Class updated code to first check for Map in servletContext
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index(@ModelAttribute("model") ModelMap model) {
Map<String, Object> myDataMap = new HashMap<String, Object>();
if (context != null && context.getAttribute("myMap")!=null)
{
myDataMap=(Map<String, Object>)context.getAttribute("myMap");
}
else
{
myDataMap = myDataProviderBean.getDataMap();
}
for (String key : myDataMap.keySet())
{
model.addAttribute(key, myDataMap.get(key));
}
return "myWebPage";
}
With this much change when I start my tomcat it loads dataMap during startTime and puts everything in servletContext which is then used by Controller Class to get results from already populated servletContext .
Please follow below step to do some processing after Application Context get loaded i.e application is ready to serve.
Create below annotation i.e
@Retention(RetentionPolicy.RUNTIME) @Target(value= {ElementType.METHOD, ElementType.TYPE}) public @interface AfterApplicationReady {}
2.Create Below Class which is a listener which get call on application ready state.
@Component
public class PostApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(PostApplicationReadyListener.class);
public static final String MODULE = PostApplicationReadyListener.class.getSimpleName();
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
ApplicationContext context = event.getApplicationContext();
String[] beans = context.getBeanNamesForAnnotation(AfterAppStarted.class);
LOGGER.info("bean found with AfterAppStarted annotation are : {}", Arrays.toString(beans));
for (String beanName : beans) {
Object bean = context.getBean(beanName);
Class<?> targetClass = AopUtils.getTargetClass(bean);
Method[] methods = targetClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AfterAppStartedComplete.class)) {
LOGGER.info("Method:[{} of Bean:{}] found with AfterAppStartedComplete Annotation.", method.getName(), beanName);
Method currentMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
LOGGER.info("Going to invoke method:{} of bean:{}", method.getName(), beanName);
currentMethod.invoke(bean);
LOGGER.info("Invocation compeleted method:{} of bean:{}", method.getName(), beanName);
}
}
}
} catch (Exception e) {
LOGGER.warn("Exception occured : ", e);
}
}
}
Finally when you start your Spring application just before log stating application started your listener will be called.
'Programing' 카테고리의 다른 글
Java에서 두 날짜 간의 차이를 어떻게 초 단위로 얻습니까? (0) | 2020.11.26 |
---|---|
방법 : Ubuntu 11.10에 Imagick (php 용) 설치 (0) | 2020.11.26 |
dplyr의 문자열 열에서 여러 값 필터링 (0) | 2020.11.26 |
지연으로 관찰 가능 항목을 생성하려면 어떻게해야합니까? (0) | 2020.11.26 |
Angular 4+ : 경로로 수동 리디렉션 (0) | 2020.11.26 |