几天前遇到的这个问题。由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@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. tomcat中配置servlet.xml的JNDI或JDBC连接数据库【原】

    tomcat中配置servlet.xml的JNDI或JDBC连接数据库 一. JNDI 1. tomcat环境 找到X:\xxx\......\apache-tomcat-6.0.39\conf\se ...

  2. SGU 271 Book Pile

    There is a pile of N books on the table. Two types of operations are performed over this pile: - a b ...

  3. Java编程思想 学习笔记4

    四.控制执行流程 1.true和false 所有条件语句都利用条件表达式的真或假来决定执行路径.注意Java不允许我们将一个数字作为布尔值使用. 2.if-else 3.迭代 while.do-whi ...

  4. java元注解 @Retention注解使用

    @Retention定义了该Annotation被保留的时间长短: 1.某些Annotation仅出现在源代码中,而被编译器丢弃: 2.另一些却被编译在class文件中,注解保留在class文件中,在 ...

  5. Python异常处理和进程线程-day09

    写在前面 上课第九天,打卡: 最坏的结果,不过是大器晚成: 一.异常处理 - 1.语法错误导致的异常 - 这种错误,根本过不了python解释器的语法检测,必须在程序运行前就修正: - 2.逻辑上的异 ...

  6. [C++]Linux之间隔时间内循环执行指定程序

    #include<time.h> #include<unistd.h>//usleep(num) #include<stdio.h> #include<std ...

  7. 【Ehcache】ehcache2.5.2缓存的使用

    缓存的名字是ehcache...老是记得是encache.... 官方PDF文档:http://www.ehcache.org/documentation/ehcache-2.5.x-document ...

  8. SpringBoot注册Servlet、Filter、Listener

    SpringBoot默认是以jar包的方式启动嵌入式的Servlet容易来启动SpringBoot的Web应用,没有web.xml文件 因此我们可以使用以下方式来注册Servlet.Filter.Li ...

  9. 【转】Python流程控制语句

    [转]Python流程控制语句 人们常说人生就是一个不断做选择题的过程:有的人没得选,只有一条路能走:有的人好一点,可以二选一:有些能力好或者家境好的人,可以有更多的选择:还有一些人在人生的迷茫期会在 ...

  10. UML和模式应用2: 迭代、进化和敏捷

    1.前言 本章主要介绍迭代.敏捷开发及UP(统一过程)的基本概念 2.基本术语 Items Note 软件开发过程 描述了构造.部署及维护软件的方式 迭代开发 是一种软件开发过程的生命周期模型,依赖短 ...