Spring 监听器 ApplicationListener 的使用

前言

在项目中我们经常会遇到在项目的各个阶段进行一些操作,此时可以使用 ApplicationListener 接口搭配 ApplicationEvent 类使用 。

ApplicationListener 支持的事件类型

 

  1. ApplicationFailedEvent:该事件为spring boot启动失败时的操作

  2. ApplicationPreparedEvent:上下文context准备时触发

  3. ApplicationReadyEvent:上下文已经准备完毕的时候触发

  4. ApplicationStartedEvent:spring boot 启动监听类

  5. SpringApplicationEvent:获取SpringApplication

  6. ApplicationEnvironmentPreparedEvent:环境事先准备

ApplicationEvent 

首先继承结构如下

EventObject
--ApplicationEvent
--SpringApplicationEvent
--ApplicationEnvironmentPreparedEvent

 

近期在工作中需要通过不同的运行环境(dev、prod)加载不同的配置文件,故本次只针对ApplicationEnvironmentPreparedEvent做不同环境下配置文件加载为例。

1、编写自己的Listener实现 ApplicationListener 接口,监听事件使用ApplicationEnvironmentPreparedEvent,实现onApplicationEvent,以下示例可实现加载不同环境下的多个文件。

public class PropertiesListenerConfig implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    private static final Logger logger = LoggerFactory.getLogger(PropertiesListenerConfig.class);
    private static final ArrayList<String> propertyFileNames = new ArrayList<>();
    private static String env = "dev";

    public PropertiesListenerConfig(String[] propertyFileName) {
        propertyFileNames.addAll(Arrays.asList(propertyFileName));
    }

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
        // 读取配置环境
        if (StringUtils.hasText(applicationEnvironmentPreparedEvent.getEnvironment().getActiveProfiles()[0])) {
            env = applicationEnvironmentPreparedEvent.getEnvironment().getActiveProfiles()[0];
        }
        // 加载配置文件
        if (propertyFileNames.size() > 0) {
            for (String propertyFileName : propertyFileNames) {
                // 配置需要载入的配置文件
                PropertiesListenerConfig.loadAllProperties(propertyFileName);
            }
        }
    }


    public static Map<String, String> propertiesMap = null;

    private static void processProperties(Properties props) throws BeansException {
        if (propertiesMap == null) {
            propertiesMap = new HashMap<>();
        }
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            try {
                // PropertiesLoaderUtils的默认编码是ISO-8859-1,在这里转码一下
                propertiesMap.put(keyStr, new String(props.getProperty(keyStr).getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void loadAllProperties(String propertyFileName) {
        try {
            Properties properties = PropertiesLoaderUtils.loadAllProperties(getEnvPropPath(propertyFileName));
            processProperties(properties);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据配置文件名,获取系统环境下的配置文件
     *
     * @param propertyFileName 配置文件名称
     * @return 系统环境下的配置文件
     */
    public static Properties getEnvPropFile(String propertyFileName) {
        Properties properties = new Properties();
        try {
            properties.load(PropertyValues.class.getClassLoader().getResourceAsStream(getEnvPropPath(propertyFileName)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return properties;
    }

    public static String getProperty(String name) {
        return propertiesMap.get(name);
    }

    public static Map<String, String> getAllProperty() {
        return propertiesMap;
    }

    /**
     * 根据配置文件名,获取系统环境下的配置文件路径
     *
     * @param propertyFileName 配置文件名称
     * @return 系统环境下的配置文件路径
     */
    private static String getEnvPropPath(String propertyFileName) {
        return "config/" + env + "/" + propertyFileName;
    }

}

 

2、监听类写完后,将监听类在启动类中加载启动

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class, org.activiti.spring.boot.SecurityAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
@EnableAsync
public class CapApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(CapApplication.class);
        // 配置文件名称
        String[] config = {"fdfs_client.properties"};
        // 根据application.yml配置环境,初始化配置文件
        application.addListeners(new PropertiesListenerConfig(config));
        application.run(args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CapApplication.class);
    }
}

3、在使用过程中,即可获得对应配置文件对象。

Properties pro = PropertiesListenerConfig.getEnvPropFile("fdfs_client.properties")

 4、如果不想将配置文件写入启动类中,也可以在启动类中只添加Listeners,在ApplicationListener实现类中去加载配置文件列表,如下:

public static void main(String[] args) {
    SpringApplication application = new SpringApplication(CapApplication.class);
    application.addListeners(new PropertiesListenerConfig());
    application.run();
}

5、需要在监听实现类中提供默认构造函数,并在实现的onApplicationEvent方法中获取配置文件列表。

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
    // 读取配置环境
    if (StringUtils.hasText(applicationEnvironmentPreparedEvent.getEnvironment().getActiveProfiles()[0])) {
        env = applicationEnvironmentPreparedEvent.getEnvironment().getActiveProfiles()[0];
    }
    logger.info("当前运行环境{}",env);
    propertyFileNames.add("fdfs_client.properties");
    // 加载配置文件
    if (propertyFileNames.size() > 0) {
        for (String propertyFileName : propertyFileNames) {
            // 配置需要载入的配置文件
            PropertiesListenerConfig.loadAllProperties(propertyFileName);
        }
    }
}

6、除了在启动类中增加监听外,也可以在application.yml中配置需要监听的类,效果相同。

 

 

下一节记录配置ApplicationListener的多种方式。。。

 

 

posted @ 2021-07-06 22:13  蓝色土耳其  阅读(1033)  评论(0编辑  收藏  举报