springbank 开发日志 一次因为多线程问题导致的applicationContext.getBean()阻塞
2017-07-08 22:47
411 查看
几天前遇到的这个问题。由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@autowired类似的方式注入到需要的类中
只能写一个工具类,实现ApplicationContextAware,取得容器,然后收到交易报文的时候,根据报文里的交易名,去取得容器中对应的transaction bean。然后根据bean的template等等信息,往下执行。
但是当我在做这件事情的时候,遇到一个奇怪的问题。这个问题我在cnblog上问过(https://q.cnblogs.com/q/95168/)。问了之后这段时间在准备一场面试,唉唉,失败了。所以今天才回过头来看这个问题:
这个TcpServer 类也是Spring容器管理的:
结果我测了一下,收到交易报文之后,走到上面代码红色的地方就“卡”住了。就像程序执行完了一样,但是没有打印出后面的debug信息,纠结了一段时间没有搞懂为什么。
今天我把spring的源代码下载下来了,DEBUG了一下,发现好像是锁的问题,因为走到了一个synchronized方法就没有后文了,可见是一直没有获取到锁
然后我又写了一些测试,把Spring启动期间所有被实例化的Singleton全部打印出来看,最后才慢慢搞明白
原来就是线程的问题。
因为啊因为啊,我上面代码里面可以看到,socket = serverSocket.accept();
这一段,是直接在TcpServer被初始化时就要运行的,但是这里阻塞的,一直等待报文的到来。就是这样,导致spring加载bean的过程,加载到这个bean也就卡住了,甚至后面还有bean根本没有机会得到实例化。
解决方式很简单,我把socket = serverSocket.accept(); 这个放到一个新开的线程里面取处理就好了。
<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(); 这个放到一个新开的线程里面取处理就好了。
相关文章推荐
- spring整合redis时 因为版本问题导致bean注入不进去问题
- SpringBank 开发日志 重新设计Action调用Service的参数传递 使用泛型解决类型转换问题
- HashMap因为多线程未同步时导致put进的元素get出来为null的分析(转)
- hadoop1.0 TaskTracker因为分布式缓存导致内存泄露的一次问题排查
- springbank 开发日志 阅读spring mvc的源代码真是受益良多
- IntelliJIdea 2016.2 使用 tomcat 8.5 调试spring的web项目时,bean被实例化两次导致timer和thread被启动了两遍的问题的解决
- SpringBank 开发日志 一种简单的拦截器设计实现
- 在开发自己淘宝客网站配置spring 遇到问题:expected single matching bean but found 2
- SpringBank 开发日志 Mybatis 使用redis 作为二级缓存时,无法通过cacheEnabled=false 将其关闭
- 多线程工作环境下MQ get操作的阻塞问题
- springbank 开发日志 springbank是如何注册handler的
- 开发日志:解决spring版本导致的Cannot find the declaration of element 'beans',查看jar中的spring的版本
- IE8浏览器缓存问题导致Ajax的GET请求只能执行一次的解决办法
- springbank 开发日志 SpringMVC是如何找到handler找到对应的方法并执行的
- 一次项目开发过程中遇到的问题--错误的表单校验导致我的整个系统宕机
- c#扩展SPRING,配置里有不存在的业务系统xml导致不能启动问题,把配置文件里有重复的服务ID找出来并写入到日志
- vs2010环境下一次因为文件名大小写问题导致无法解析的外部符号问题
- Strategy 策略模式 在 Spring 开发中的应用 包括事务管理,日志管理(logger),IoC容器根据bean定义的内容实例化等
- springbank 开发日志 springbank是如何执行一个handler的requestMapping对应的方法的
- Spring 在多线程中,bean的注入问题