利用ApplicationListener和ContextRefreshedEvent加载自己的beanPool

Posted 振宇要低调

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用ApplicationListener和ContextRefreshedEvent加载自己的beanPool相关的知识,希望对你有一定的参考价值。

基本原理:

  1、Spring的ApplicationListener和ContextRefreshedEvent一般都是成对出现的。

  2、在IOC的容器的启动过程中,当所有的bean都已经处理完成之后,spring ioc容器会有一个发布事件的动作。

  3、当该发布事件的监听者监听到此动作时,ApplicationListener接口实例中的onApplicationEvent(E event)方法就会被调用。

  4、调用该方法时,通过父类找到实现类,再根据业务场景(以下示例中为serviceID),将对应的bean填充至beanPool中。

  5、这样,在编写业务代码时,直接通过serviceID就能找到对应处理的类

 

上代码

父类及各实现子类:

package com.test;

/**
 * @author zyydd
 * @date 2019/12/9 10:37
 */
public abstract class TestServiceBase {
    protected abstract String getServiceId();

    public abstract void handle();
}


package com.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @author zyydd
 * @date 2019/12/9 10:36
 */
@Service
public class AtestService extends TestServiceBase {
    private static final Logger logger = LoggerFactory.getLogger(AtestService.class);

    @Value("${testService.serviceId.aTest}")
    private String serviceId;

    @Override
    protected String getServiceId() {
        return serviceId;
    }

    @Override
    public void handle() {
        logger.info("hi everyOne, this is A!");
    }
}


package com.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @author zyydd
 * @date 2019/12/9 10:36
 */
@Service
public class BtestService extends TestServiceBase {
    private static final Logger logger = LoggerFactory.getLogger(BtestService.class);

    @Value("${testService.serviceId.bTest}")
    private String serviceId;

    @Override
    protected String getServiceId() {
        return serviceId;
    }

    @Override
    public void handle() {
        logger.info("hi everyOne, this is B!");
    }
}

其中,serviceID是通过读取yaml中的配置,填充进去的,yaml配置:

testService:
  serviceId:
    aTest: 1001
    bTest: 1002

 

自建的beanPool,系统启动时填充,业务流程中通过serviceID获取:

package com.test;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;

/**
 * @author zyydd
 * @date 2019/12/9 10:42
 */
@Service
public class TestServicePool {
    private HashMap<String, TestServiceBase> testServiceMap = new HashMap<>(16);

    public TestServiceBase get(String serviceId) {
        return testServiceMap.get(serviceId);
    }

    public void put(String serviceId, TestServiceBase testService) {
        if (StringUtils.isEmpty(serviceId) || testService == null) {
            return;
        }
        this.testServiceMap.put(serviceId, testService);
    }
}

 

ApplicationListener接口实例,填充beanPool:

package com.test;

import com.**.util.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Map;

/**
 * @author zyydd
 * @date 2019/12/9 10:46
 */
@Component
public class TestServiceLoadListener implements ApplicationListener<ContextRefreshedEvent> {
    private static final Logger logger = LoggerFactory.getLogger(TestServiceLoadListener.class);

    @Autowired
    private TestServicePool testServicePool;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            logger.info("TestServiceLoadListener 开始加载");
            //根据父类(TestServiceBase)加载子类bean
            Map<String, TestServiceBase> beanMap = event.getApplicationContext().getBeansOfType(TestServiceBase.class);
            logger.info("TestServiceLoadListener 加载结果={}", JsonUtils.toJSONString(beanMap));
            //将子类挨个填充到testServicePool中
            if (CollectionUtils.isEmpty(beanMap)) {
                logger.error("TestServiceLoadListener 加载失败,无法获取TestServiceBase的子类!");
                return;
            } else {
                for (TestServiceBase bean : beanMap.values()) {
                    testServicePool.put(bean.getServiceId(), bean);
                    logger.info("TestServiceLoadListener 加载一个: serviceid={} bean={}", bean.getServiceId(), bean.getClass().getName());
                }
            }
        }
    }
}

 

单元测试类:

package com.**.service;

import com.**.web.Application;
import com.test.TestServiceBase;
import com.test.TestServicePool;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author zyydd
 * @date 2019/6/3 10:54
 */
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class TestServiceTest {
    private static final Logger logger = LoggerFactory.getLogger(TestServiceTest.class);

    @Autowired
    private TestServicePool testServicePool;

    @Test
    public void testTestServicePool() {
        TestServiceBase a = testServicePool.get("1001");
        logger.info(a.getClass().getName());
        a.handle();
    }

}

 

单元测试执行结果:

2019-12-09 11:12:26.100 INFO  [main] com.test.TestServiceLoadListener [28] - TestServiceLoadListener 开始加载
2019-12-09 11:12:26.112 INFO  [main] com.test.TestServiceLoadListener [31] - TestServiceLoadListener 加载结果={"atestService":{},"btestService":{}}
2019-12-09 11:12:26.113 INFO  [main] com.test.TestServiceLoadListener [39] - TestServiceLoadListener 加载一个: serviceid=1001 bean=com.test.AtestService
2019-12-09 11:12:26.113 INFO  [main] com.test.TestServiceLoadListener [39] - TestServiceLoadListener 加载一个: serviceid=1002 bean=com.test.BtestService

2019-12-09 11:12:27.067 INFO  [main] com.**.service.TestServiceTest [30] - com.test.AtestService
2019-12-09 11:12:27.067 INFO  [main] com.test.AtestService [26] - hi everyOne, this is A!

 

以上是关于利用ApplicationListener和ContextRefreshedEvent加载自己的beanPool的主要内容,如果未能解决你的问题,请参考以下文章

Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法

ApplicationListener机制

ApplicationListener机制

Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法

SpringBoot加载应用事件监听器

SpringBoot加载应用事件监听器