009-Spring Boot 事件監聽、監聽器配置與方式、spring、Spring boot內置事件

1、概念

1.事件監聽的流程

  步驟1、自定義事件,通常是繼承ApplicationEvent抽象類java

  步驟2、定義事件監聽器,通常是實現ApplicationListener接口web

  步驟3、啓動時,須要將監聽器加入到Spring容器中spring

  步驟4、發佈事件express

對於配置監聽器的方式【即第三步】apache

  方式1、app.addListeners(new MyApplicationListener());添加監聽器springboot

  方式2、把監聽器使用歸入Spring配置中管理如使用@Component標註app

  方式3、再application.properties中添加context.listener.classes配置項配置less

  方式4、使用註解@EventListener在方法上,且該類須要在Spring上管理ide

二、示例【方式一】:

步驟1、自定義事件MyApplicationEventui

package com.lhx.spring.springboot_event;

import org.springframework.context.ApplicationEvent;

/**
 * 定義事件
 * @author Administrator
 *
 */
public class MyApplicationEvent extends ApplicationEvent {
    private static final long serialVersionUID = 1L;

    public MyApplicationEvent(Object source) {
        super(source);
    }
}
View Code

步驟2、定義事件監聽器MyApplicationListener 

package com.lhx.spring.springboot_event;

import org.springframework.context.ApplicationListener;

public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {

    @Override
    public void onApplicationEvent(MyApplicationEvent event) {
        System.out.println("接收到事件:" + event.getClass());
    }

}
View Code

步驟3、在App啓動程序中添加以及發佈

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        // ConfigurableApplicationContext context = SpringApplication.run(App.class,
        // args);
        SpringApplication app = new SpringApplication(App.class);
        app.addListeners(new MyApplicationListener());
        ConfigurableApplicationContext context = app.run(args);
        context.publishEvent(new MyApplicationEvent(new Object()));
        context.close();
    }
}

三、示例【方式二】:

注意:其實在示例步驟三,也能夠用註解方式將時間監聽器歸入Spring管理中

步驟1、與示例一一致

步驟2、將事件監聽器添加@Component註解。

步驟3、啓動類

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);
        //app.addListeners(new MyApplicationListener());
        ConfigurableApplicationContext context = app.run(args);
        context.publishEvent(new MyApplicationEvent(new Object()));
        context.close();
    }
}

四、示例【方式四】:

步驟1、與示例一一致

步驟2、與示例一一致

步驟3、增長單獨處理類

package com.lhx.spring.springboot_event;

import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyEventHandle {
    @EventListener
    public void event(MyApplicationEvent event) {
        System.out.println("MyEventHandle 接收到事件:" + event.getClass());
    }
    

    @EventListener
    public void event2(ContextStoppedEvent event) {
        System.out.println("應用中止  接收到事件:" + event.getClass());
    }
}
View Code

步驟3、啓動類

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);、
        ConfigurableApplicationContext context = app.run(args);
        context.publishEvent(new MyApplicationEvent(new Object()));
        context.close();
    }
}
View Code

2、配置監聽器的方式原理

1.方式三實現,在application.properties中添加context.listener.classes配置項配置

查看:DelegatingApplicationListener

public class DelegatingApplicationListener
        implements ApplicationListener<ApplicationEvent>, Ordered {

    // NOTE: Similar to org.springframework.web.context.ContextLoader

    private static final String PROPERTY_NAME = "context.listener.classes";

核心邏輯

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
                    ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
            if (delegates.isEmpty()) {
                return;
            }
            this.multicaster = new SimpleApplicationEventMulticaster();
            for (ApplicationListener<ApplicationEvent> listener : delegates) {
                this.multicaster.addApplicationListener(listener);
            }
        }
        if (this.multicaster != null) {
            this.multicaster.multicastEvent(event);
        }
    }

    @SuppressWarnings("unchecked")
    private List<ApplicationListener<ApplicationEvent>> getListeners(
            ConfigurableEnvironment environment) {
        if (environment == null) {
            return Collections.emptyList();
        }
        String classNames = environment.getProperty(PROPERTY_NAME);
        List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>();
        if (StringUtils.hasLength(classNames)) {
            for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
                try {
                    Class<?> clazz = ClassUtils.forName(className,
                            ClassUtils.getDefaultClassLoader());
                    Assert.isAssignable(ApplicationListener.class, clazz, "class ["
                            + className + "] must implement ApplicationListener");
                    listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils
                            .instantiateClass(clazz));
                }
                catch (Exception ex) {
                    throw new ApplicationContextException(
                            "Failed to load context listener class [" + className + "]",
                            ex);
                }
            }
        }
        AnnotationAwareOrderComparator.sort(listeners);
        return listeners;
    }
View Code

二、方式四實現

查看:EventListenerMethodProcessor的processBean

    protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
        if (!this.nonAnnotatedClasses.contains(targetType)) {
            Map<Method, EventListener> annotatedMethods = null;
            try {
                annotatedMethods = MethodIntrospector.selectMethods(targetType,
                        new MethodIntrospector.MetadataLookup<EventListener>() {
                            @Override
                            public EventListener inspect(Method method) {
                                return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
                            }
                        });
            }
            catch (Throwable ex) {
                // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
                }
            }
            if (CollectionUtils.isEmpty(annotatedMethods)) {
                this.nonAnnotatedClasses.add(targetType);
                if (logger.isTraceEnabled()) {
                    logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
                }
            }
            else {
                // Non-empty set of methods
                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        if (factory.supportsMethod(method)) {
                            Method methodToUse = AopUtils.selectInvocableMethod(
                                    method, this.applicationContext.getType(beanName));
                            ApplicationListener<?> applicationListener =
                                    factory.createApplicationListener(beanName, targetType, methodToUse);
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener)
                                        .init(this.applicationContext, this.evaluator);
                            }
                            this.applicationContext.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                            beanName + "': " + annotatedMethods);
                }
            }
        }
    }
View Code

EventListener

                annotatedMethods = MethodIntrospector.selectMethods(targetType,
                        new MethodIntrospector.MetadataLookup<EventListener>() {
                            @Override
                            public EventListener inspect(Method method) {
                                return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
                            }
                        });

查看for

                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        if (factory.supportsMethod(method)) {
                            Method methodToUse = AopUtils.selectInvocableMethod(
                                    method, this.applicationContext.getType(beanName));
                            ApplicationListener<?> applicationListener =
                                    factory.createApplicationListener(beanName, targetType, methodToUse);
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener)
                                        .init(this.applicationContext, this.evaluator);
                            }
                            this.applicationContext.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                }

其中factory即EventListenerFactory factory

/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.event;

import java.lang.reflect.Method;

import org.springframework.context.ApplicationListener;

/**
 * Strategy interface for creating {@link ApplicationListener} for methods
 * annotated with {@link EventListener}.
 *
 * @author Stephane Nicoll
 * @since 4.2
 */
public interface EventListenerFactory {

    /**
     * Specify if this factory supports the specified {@link Method}.
     * @param method an {@link EventListener} annotated method
     * @return {@code true} if this factory supports the specified method
     */
    boolean supportsMethod(Method method);

    /**
     * Create an {@link ApplicationListener} for the specified method.
     * @param beanName the name of the bean
     * @param type the target type of the instance
     * @param method the {@link EventListener} annotated method
     * @return an application listener, suitable to invoke the specified method
     */
    ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);

}
View Code

3、spring、Spring boot內置事件

1.Spring

jar包:Spring-context-4.3.13.RELEASE

  包:org.springframwork.context.event;

經常使用:ContextClosedEvent、ContextStartedEvent、ContextStopedEvent

示例

@Component
public class MyEventHandle {
    @EventListener
    public void event2(ContextStoppedEvent event) {
        System.out.println("應用中止  接收到事件:" + event.getClass());
    }
}

固然:app中Context要中止

@SpringBootApplication
public class App {
    public static void main(String[] args) {        
        SpringApplication app = new SpringApplication(App.class);
        ConfigurableApplicationContext context = app.run(args);
        context.publishEvent(new MyApplicationEvent(new Object()));
        context.stop();
    }
}

2.Spring-boot

jar包:Spring-boot-1.5.9.RELEASE

  包:org.springframework.boot.context.event;

經常使用:ApplicationEnvironmentPreparedEvent、ApplicationFailedEvent等

相關文章
相關標籤/搜索