基本原理:

  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的更多相关文章

  1. 利用python进行数据加载和存储

    1.文本文件 (1)pd.read_csv加载分隔符为逗号的数据:pd.read_table从文件.URL.文件型对象中加载带分隔符的数据.默认为制表符.(加载为DataFrame结构) 参数name ...

  2. WPF当属性值改变时利用PropertyChanged事件来加载动画

    在我们的程序中,有时我们需要当绑定到UI界面上的属性值发生变化从而引起数据更新的时候能够加载一些动画,从而使数据更新的效果更佳绚丽,在我们的程序中尽量将动画作为一种资源放在xaml中,而不是在后台中通 ...

  3. 图片利用 new Image()预加载原理 和懒加载的实现原理

    二:预加载和懒加载的区别 预加载与懒加载,我们经常经常用到,这些技术不仅仅限于图片加载,我们今天讨论的是图片加载: 图片预加载:顾名思义,图片预加载就是在网页全部加载之前,提前加载图片.当用户需要查看 ...

  4. 利用CAReplicatorLayer实现的加载动画

    在上一篇中,笔者简要介绍了CAReplicatorLayer,在本篇中,将介绍具体的实用价值. 实用CAReplicatorLayer作为核心技术实现加载动画. 首先,创建一个UIView的子类 @i ...

  5. 利用LruCache为GridView加载大量本地图片完整示例

    MainActivity如下: package cc.testlrucache; import android.os.Bundle; import android.widget.GridView; i ...

  6. 利用青瓷布局自定义加载的场景,而不是自己改写qici-loading

    加载界面如果全部通过自己手动布局不仅不美观,还很难控制.借用原生的场景切换加载效果,来实现我们游戏的加载效果. 没有做加载修改的原来的加载顺序:   黑乎乎界面->(游戏定制的加载)你的第一个场 ...

  7. 利用css实现页面加载时旋转动画

    有时浏览一些网站时在刚加载页面时候会出现一个滚动动画如下图,特别是对于一些移动端的站点或者混合应用来说应该用户体验会好很多,扒了下页面发现是用css样式控制的,于是把页面以及css样式赋值了下来, h ...

  8. C# DataGridVie利用model特性动态加载列

    今天闲来无事看到ORm的特性映射sql语句.我就想到datagridview也可以用这个来动态添加列.这样就不用每次都去界面上点开界面填列了. 代码简漏希望有人看到了能指点一二. 先定义好Datagr ...

  9. Android框架Volley之:利用Imageloader和NetWorkImageView加载图片

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: < ...

随机推荐

  1. mini Redis(项目 二)

    一个仿Redis的内存数据库(主要用来做命令解析)服务端,  客户端使用的开源工具 : https://dom4j.github.io/     github:https://github.com/h ...

  2. ASP.NET MVC IOC 之 Autofac(三)-webform中应用

    在webform中应用autofac,只有global中的写法不一样,其他使用方式都一样 nuget上引用: global中的写法: private void AutoFacRegister() { ...

  3. leetcode5086:smallest-subsequence-of-distinct-characters

    leetcode5086 问题描述 给定一个字符串s,其中只包含小写字母.求s的一个子序列t.要求t包含s中的全部字符.如果答案有多个,输出字典序最小的那个子序列. 解法描述 首先,为s中每个字符打标 ...

  4. while(n)什么意思?

    1.n是bool型变量时,就是代表n为true时运行循环(bool表示布尔型变量,也就是逻辑型变量的定义符,以英国数学家.布尔代数的奠基人乔治·布尔(George Boole)命名. bool类似于f ...

  5. 8皇后问题SQL求解(回溯算法)

    问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一 ...

  6. 3.redis 都有哪些数据类型?分别在哪些场景下使用比较合适?

    作者:中华石杉 面试题 redis 都有哪些数据类型?分别在哪些场景下使用比较合适? 面试官心理分析 除非是面试官感觉看你简历,是工作 3 年以内的比较初级的同学,可能对技术没有很深入的研究,面试官才 ...

  7. c#执行sql超时

    超时分为多种,SqlConnection有超时选项, SqlDataAdapter也有超时选项设置如下: SqlConnection:就用链接字符串给予的Timeout设置就行单位秒: SqlData ...

  8. Jmeter 使用自定义变量

    有些情况下比如发起测试时URL的主机名和端口需要在采样器中出现多次,这样就有个问题,当测试的主机更改时, 我们需要修改主机名称,这时就需要修改多个地方,如果多的情况会有遗漏.如果我们在配置脚本的时候, ...

  9. nginx上部署PHP

    环境:centos7  nginx1.16.1 (1)先将tp源代码下载到nginx的站点目录下 注意:存放tp的目录要有可执行权限,否则无法进入目录,访问报403 (2)servr配置: serve ...

  10. 学Redis

    Redis 简介 Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key - value 数据库 Redis 与 其他 key - value 缓存产品有以下三个特点: Redis ...