基本原理:
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!