几天前遇到的这个问题。由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@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(); 这个放到一个新开的线程里面取处理就好了。

springbank 开发日志 一次因为多线程问题导致的applicationContext.getBean()阻塞的更多相关文章

  1. SpringBank 开发日志 使用maven构建dubbo服务的可执行jar包

    写这篇日志的时候,我已经完成了这个目标,并且中间经历了一次面试.现在回过头看,已经觉得印象不那么深刻了,果然还是一边思考,一边记录这样最好.但我还是严格要求自己,从新做了梳理,对相关配置进行了整理和说 ...

  2. SpringBank 开发日志 Mybatis 使用redis 作为二级缓存时,无法通过cacheEnabled=false 将其关闭

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  3. SpringBank 开发日志 一种简单的拦截器设计实现

    当交易由Action进入Service之前,需要根据不同的Service实际负责业务的不同,真正执行Service的业务逻辑之前,做一些检查工作.这样的拦截器应该是基于配置的,与Service关联起来 ...

  4. springbank 开发日志 springbank是如何注册handler的

    这要从DefaultAnnotationHandlerMapping这个类说起,该类被@Component注释,该类被Spring IOC容器实例化之后,将会执行其initApplicationCon ...

  5. springbank 开发日志 Spring启动过程中对自定义标签的处理

    这篇随笔的许多知识来源于:http://www.importnew.com/19391.html 之所以会去看这些东东,主要是希望能够模仿spring mvc的处理流程,做出一套合理的交易处理流程. ...

  6. SpringBank 开发日志 重新设计Action调用Service的参数传递 使用泛型解决类型转换问题

    之前想的比较简单,请求到达controller的时候,传给action的参数没有经过任何封装,就是一个Map.然后action再调用service的时候,传递的参数也是map @Controller ...

  7. springbank 开发日志 springbank是如何执行一个handler的requestMapping对应的方法的

    占位 从dispatcher说起,方法doDispatch(Map request)的参数request是一个通过解析来报报文新城的map //获取HandlerExecutionChain,其中封装 ...

  8. springbank 开发日志 SpringMVC是如何找到handler找到对应的方法并执行的

    从DispatcherServlet说起,本文讨论的内容都是DispatcherServlet的doDispatch方法完成 mappedHandler是一个HandlerExecutionChain ...

  9. springbank 开发日志 阅读spring mvc的源代码真是受益良多

    决定模仿spring mvc的dispatcher->handlerMapping(return executorChain)->handler.execute 这样的流程之后,就开始看s ...

随机推荐

  1. java实现获取当前年月日 小时 分钟 秒 毫秒

    java代码实现如下 view source print?     /**      * 英文简写(默认)如:2010-12-01      */     public static String F ...

  2. PHP7 学习笔记(六)403 Forbidden - WAMP Server 2.5

    今天在wamp目录下有一个项目:comment 我在我的Windows 7机器上安装了WAMP版本2.5. 当浏览器浏览到本地主机时,WAMP服务器页面是可见的. 但是当我浏览到我的本地主机在我的移动 ...

  3. 用贪心算法近似求解 Loading Balance 问题(作业调度的负载均衡)

    一,Loading Balance 问题描述:有 m 台相同的机器及 n 个作业,其中 m={M(1),M(2),……M(m)}.n = {J(1),J(2),……J(n)}.每个作业都有一个处理时间 ...

  4. IPv4套接字地址结构

    一.IPv4套接字地址结构(POSIX定义) (1)长度字段sin_len是为增加对OSI协议的支持而随4.3BSD-Reno添加的:并不是所有的厂家都支持套接字地址结构的长度字段,而且POSIX规范 ...

  5. 工控安全入门之Ethernet/IP

    这一篇依然是协议层面的,协议层面会翻译三篇,下一篇是电力系统中用的比较多的DNP3.这一篇中大部分引用的资料都可以访问到,只有一篇reversemode.com上的writeup(http://rev ...

  6. C# Regex正则常用方法的使用

    using System; using System.Collections; using System.Configuration; using System.Data; using System. ...

  7. gulp+webpack构建配置

    使用构建工具之前我觉得前端好蠢,css没有变量,不能写循环,为了兼容要写好多前缀,hmtl写多页面中有同一个header,我就粘贴复制,然后修改的时候每个都要改. 我还不会压缩和合并,每次都要按F5刷 ...

  8. kafka.common.KafkaException: Socket server failed to bind to hdp1:9092: Cannot assign requested address.

    ERROR [KafkaServer id=1] Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.K ...

  9. _vimrc(VimScript脚本语言学习)

    Windows下 syntax on "高亮 "缩进 set cindent "set cin set smartindent "set si set auto ...

  10. 现代C++之理解decltype

     现代C++之理解decltype decltype用于生成变量名或者表达式的类型,其生成的结果有的是显而易见的,可以预测的,容易理解,有些则不容易理解.大多数情况下,与使用模板和auto时进行的类型 ...