springbank 开发日志 一次因为多线程问题导致的applicationContext.getBean()阻塞
几天前遇到的这个问题。由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@autowired类似的方式注入到需要的类中
<op:transaction id="Recharge" template="TransTemplate"></op:transaction>
<op:transaction id="QueryAgreementAcct" template="TransTemplate"></op:transaction>
只能写一个工具类,实现ApplicationContextAware,取得容器,然后收到交易报文的时候,根据报文里的交易名,去取得容器中对应的transaction bean。然后根据bean的template等等信息,往下执行。
但是当我在做这件事情的时候,遇到一个奇怪的问题。这个问题我在cnblog上问过(https://q.cnblogs.com/q/95168/)。问了之后这段时间在准备一场面试,唉唉,失败了。所以今天才回过头来看这个问题:
public class TcpServer implements ApplicationContextAware{
private OpenbankExecutor executor;
private int port;
private PacketHandler packetHandler;
private ServerSocket serverSocket;
private Socket socket;
private ApplicationContext applicationContext;
private final Logger log = LoggerFactory.getLogger(getClass());
public void init() throws IOException {
serverSocket = new ServerSocket(port);
log.debug("TcpServer 成功启动");
while(true) {
socket = serverSocket.accept();
System.out.println("收到socket请求");
executor.execute(new Runnable() { @Override
public void run() {
try {
Map context = packetHandler.handle(socket.getInputStream());
String tranCode = (String) context.get("tranCode");
Assert.hasText(tranCode);
Transaction transaction = (Transaction) applicationContext.getBean(tranCode);
Template template = (Template) applicationContext.getBean(transaction.getTemplate());
log.debug("transaction: "+transaction.getId());
log.debug("transaction: "+template.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
这个TcpServer 类也是Spring容器管理的:
<bean id="tcpServer" class="com.openbank.portal.server.TcpServer" init-method="init">
<property name="executor" ref="openbankThreadPool"/>
<property name="port" value="${tcp.port}"/>
<property name="packetHandler" ref="xmlpacketHandler"/>
</bean>
结果我测了一下,收到交易报文之后,走到上面代码红色的地方就“卡”住了。就像程序执行完了一样,但是没有打印出后面的debug信息,纠结了一段时间没有搞懂为什么。
今天我把spring的源代码下载下来了,DEBUG了一下,发现好像是锁的问题,因为走到了一个synchronized方法就没有后文了,可见是一直没有获取到锁
然后我又写了一些测试,把Spring启动期间所有被实例化的Singleton全部打印出来看,最后才慢慢搞明白
原来就是线程的问题。
因为啊因为啊,我上面代码里面可以看到,socket = serverSocket.accept();
这一段,是直接在TcpServer被初始化时就要运行的,但是这里阻塞的,一直等待报文的到来。就是这样,导致spring加载bean的过程,加载到这个bean也就卡住了,甚至后面还有bean根本没有机会得到实例化。
解决方式很简单,我把socket = serverSocket.accept(); 这个放到一个新开的线程里面取处理就好了。
最新文章
- JS/CSS收藏
- 金字塔Lucas-Kanande光流算法实现
- 开始学习c语言
- AMBA
- c# 筛选进程命令行,得其ProcessId(唯一标示符,简称pid),再通过pid结束进程
- paip.互联网产品要成功的要素
- windows7 中开启无线热点
- zabbix命令:zabbix_get获取item数据
- Global::pickSpecificClass_DNT
- Haxe数据类型
- Android中Dialog的使用
- 分析Sizzle引擎
- iOS程序进入后台,延迟指定时间退出
- toastr操作完成提示框
- 带拦截器配置的 struts.xml文件
- python之 自动补全 tab
- 自学python 8.
- PHP抽象类
- spring boot+ Intellj idea devtools 设置热部署
- git学习入门
热门文章
- Error: failed to execute &#39;C:\Keil\ARM\ARMCC&#39;的解决办法
- tarjan,树剖,倍增求lca
- DCNN models
- Nginx PHP支持
- JavaScript之函数存储[摘]
- 自己对Java的一些认识
- HTML5的学习(一)HTML5标签
- TypeError: view must be a callable or a list/tuple in the case of include()
- SpringMVC——SpringMVC 的入门案例
- Ngnix + Tomcat负载均衡架构