利用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 用法