`
fujohnwang
  • 浏览: 153559 次
社区版块
存档分类
最新评论

Spring使用中的陷阱和诀窍(Spring Gochas and Tips)

    博客分类:
  • Tech
阅读更多

Spring使用中的陷阱和诀窍(Spring Gochas and Tips)


本来想就这个写一系列的东西,不过, 很难拼凑足够数量的案例(自然也成不了书),所以, 先暂且随手捡两个掰一掰, 一个黑的,一个红的...

1. 陷阱(Gochas)

1.1. 说事儿

话说PACMAN项目需要对DTC来的消息处理过程进行优化,这活儿到我头上了, 本来吧, 小事儿, 虽然数据量一下子从两三万蹿到100万左右, 首先咱可以提高worker threads的数量嘛, 实在不行, 咱再考虑分布, 但这是宏观上的, 这里的小陷阱存在于细节中, 有句话叫做“The problem isn't design; it's implementation.”, 说的就是这个道理, 不过,这有些扯远了...

程序重构完了,该测试了。 第一次启动Weblogic, 测了一轮, 有些地方需要持续修正, 程序部署之后, 重新启动Weblogic,当当, 异常来啦!

javax.jms.JMSException: Duplicate durable subcription detected
        at com.tibco.tibjms.Tibjmsx.buildException(Tibjmsx.java:562)
        at com.tibco.tibjms.TibjmsSession._createConsumer(TibjmsSession.java:437)
        at com.tibco.tibjms.TibjmsSession._createConsumer(TibjmsSession.java:366)
        at com.tibco.tibjms.TibjmsSession.createDurableSubscriber(TibjmsSession.java:3950)
        at com.tibco.tibjms.TibjmsTopicSession.createDurableSubscriber(TibjmsTopicSession.java:114)
        at com.citigroup.posmgmt.util.consumer.JMSTopicConsumer.initialiseService(JMSTopicConsumer.java:105)
        at com.citigroup.posmgmt.util.consumer.DTCMsgConsumer.initService(DTCMsgConsumer.java:146)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1133)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1095)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:396)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:145)
        at com.citigroup.posmgmt.ejb.AdminMsgHandler.startRealTimeConsumer(AdminMsgHandler.java:135)
        at com.citigroup.posmgmt.ejb.AdminMsgHandler.onMessage(AdminMsgHandler.java:68)
        at weblogic.ejb.container.internal.MDListener.execute(MDListener.java:429)
        at weblogic.ejb.container.internal.MDListener.transactionalOnMessage(MDListener.java:335)
        at weblogic.ejb.container.internal.MDListener.onMessage(MDListener.java:291)
        at weblogic.jms.client.JMSSession.onMessage(JMSSession.java:4072)
        at weblogic.jms.client.JMSSession.execute(JMSSession.java:3962)
        at weblogic.jms.client.JMSSession$UseForRunnable.run(JMSSession.java:4490)
        at weblogic.work.ExecuteRequestAdapter.execute(ExecuteRequestAdapter.java:21)
        at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:145)
        at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:117)
				

他娘的, 不能把?!怎么隐约记得之前好象测试其他地方的时候也遇到过类似的问题那? 不过, 那时候也不知道怎么糊弄过去了, 看来不成, 确实哪里有问题啊!

EMS服务器还是人家NY的, 咱也上不去阿, 能上去也好看一下是不是其他连接在那里, 到底谁在捣乱, 发信给NY,告诉没权限, nnd, google吧, 围绕EMS和这个异常折腾了好是一通, 未果。 忘了都折腾啥了, 反正我是彻底的翻了一遍code和spring配置文件, destroy方法真真切切的在那里,我都挨个字母得对名称啊, 对完了也没发现有问题。

最后, 不管了, 出去溜达了一圈, 回头一想, tnnd,不会之前的代码没有触发对象销毁的行为吧?不然,这多出来的连接到底哪里来的?好像除了我也没人在做同样的事情啊! 查入口类StartupManager, 得, 还真他娘的是这么回事, shutDownService()方法只有抛出Exception的情况下才会被调用到, 正常情况下, 反而没有被调用, 靠, 这代码都跑了2年了, 这帮人居然没发现, 还好意思说, 代码都跑了两年了,没有遇到这样的问题啊, 这Batch从市场关闭到市场开启的近乎半天时间里, 你就算不关Connection, 那服务器那边也会按照超时给你“咔嚓”掉吧?这样的跑了两年当然没问题啦!

1.2. 结论

生活在Spring容器中的对象, 他们的生命周期是由容器来管理的, 但是, 仅仅通过实现DisposableBean接口或者通过destroy-method配置项, 甚至通过JSR250的@PreDestroy标注, 容器并不会在程序退出的时候,自动调用这些对象销毁的回调,我们必须在程序的主入口类或者其它合适的位置明确告知Spring容器, “哥们, 我要下班了,你把那些家伙都收拾了吧!”, 之后, 你通过以上所有方式指定的对象销毁逻辑才会被调用,否则, 哼哼...

用行话来说就是, 如果你使用的是BeanFactory类型的IoC容器,那么,你最好在容器构造完成后, 保险起见,顺便加上以下这样的代码片断:

Runtime.getRuntime().addShutdownHook(new Thread(){
		@Override
		public void run() {
		    if(beanFactory != null){
			beanFactory.destroySingletons();
		    }
		}
    });
				

如果你使用的是ApplicationContext类型的IoC容器,那么, 与上面类似:

ApplicationContext ctx = ...;
((AbstractApplicationContext)ctx).registerShutdownHook();
				

当然了, 道理实际上跟上面BeanFactory对应的处理差不多。

这样的处理虽然不能保证100%的安全,不过,只要你不是太粗鲁的对待你的应用程序,比如kill -9或者直接System.halt()之类, 这道安全网还是必要的。

Note
[Note]

这个问题实际上早就写入了《Spring揭密》之中,只不过, 既然书还没出来,那就再重复一下这一言论吧!

2. 诀窍(Tips)

2.1. 说事儿

还是跟JMS连接有关, 话说纽约DDI Team某天突然发彪,说, “要连接到我们的EMS服务器订阅消息,必须通过用户和密码验证, 那种不验证就使用我们服务的日子已经一去不复返了。

收到旨意之后, 你得赶快行动啊, 不然,下个release拿不到trades信息可就是你自己的问题了, 还好啦, 现在的Subscriber已经提供了这样的支持, 直接设置相应的username和pasword就行了。 不过那,如果你是通过JmsTemplate或者MessageListenerContainer来发送或者接受消息的话, 你该怎么做哪?! 也只是通过为JmsTemplate或者MessageListenerContainer提供连接的用户名和密码设置就行了?呵呵,倒是找找看, 你是否能找到相应的setter方法吧。

2.2. 结论

摘录一段别人的代码如下:

            if(String.valueOf(userName).trim().length()>0) {
                topicConn = connFactory.createTopicConnection(userName,password);
            } else {
                topicConn = connFactory.createTopicConnection();
            }
				

如果你觉得JmsTemplate或者MessageListenerContainer在实现的时候也是这样处理的,那么, 在上面的那个场景中,你将浪费某些精力和时间去寻找这个方向上的答案, 但即使你去查代码,估计你也不会有啥收获。实际上,针对这个问题, Spring框架已经提供了对应的解决方案, 但是, 解决问题的角度不同而已。

Spring提供了一个UserCredentialsConnectionFactoryAdapter, 通过它,对你提供给JmsTemplate或者MessageListenerContainer使用的ConnectionFactory稍微“打扮”一下就行了, 例如:

ConnectionFactory cf = (ConnectionFactory) ctx.lookup(connectionFactoryJndiName);

UserCredentialsConnectionFactoryAdapter connectionFactoryAdaptor = new UserCredentialsConnectionFactoryAdapter();
connectionFactoryAdaptor.setTargetConnectionFactory(cf);
connectionFactoryAdaptor.setUsername("ddi_admin");
connectionFactoryAdaptor.setPassword("ddi_admin");
... // ***
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactoryAdaptor);
				

现在, 验证信息可以生效了。 说白了, 还是包装,包装,再包装,最终都是为了“偷梁换柱”!

Caution
[Caution]

如果是使用JmsTemplate来发送消息,为了避免JmsTemplate内部不断创建新的连接, 保险起见, 可以使用SingleConnectionFactory对ConnectionFactory再包装一层(当然了,如果拿到的ConnectionFactory早已配置了连接池来控制资源的使用,也可以不用这么做),例如:

ConnectionFactory cf = (ConnectionFactory) ctx.lookup(connectionFactoryJndiName);

UserCredentialsConnectionFactoryAdapter connectionFactoryAdaptor = new UserCredentialsConnectionFactoryAdapter();
connectionFactoryAdaptor.setTargetConnectionFactory(cf);
connectionFactoryAdaptor.setUsername("ddi_admin");
connectionFactoryAdaptor.setPassword("ddi_admin");

final SingleConnectionFactory singleCf = new SingleConnectionFactory(connectionFactoryAdaptor); 
										  
	Runtime.getRuntime().addShutdownHook(new Thread() {
	    @Override
	    public void run() {
		try {
		    singleCf.destroy();
		} catch (Exception e) {
		    logger.error("failed to destroy single connection factory.\n");
		    logger.error(ExceptionUtils.getFullStackTrace(e));
		}
	    }
	});
	
JmsTemplate jmsTemplate = new JmsTemplate(singleCf);
					

安全第一, 安全第一...

Know Spring And Have Fun With Spring.

分享到:
评论

相关推荐

    Beginning Spring Boot 2 Applications and Microservices with the Spring Framework

    Siva Prasad Reddy Spring is the most popular Java-based framework for building enterprise ...applications quickly and easily, and the inner workings of Spring Boot using easy-to-follow examples.

    在非spring注解类中使用spring容器中的bean_普通类中使用yml配置文件中的配置信息

    在非spring注解类中使用spring容器中的bean_普通类中使用yml配置文件中的配置信息,在大数据采集项目中用到的,已经测试过了

    springboot 使用spring cache缓存 和 使用fastjson配置redis系列化

    springboot 使用spring cache缓存 和 使用fastjson配置redis系列化,springboot 使用spring cache缓存 和 使用fastjson配置redis系列化,springboot 使用spring cache缓存 和 使用fastjson配置redis系列化,springboot ...

    Spring中文API帮助文档

    spring中文API文档 spring中文API文档 spring中文API文档 spring中文API文档

    Getting started with Spring Framework: covers Spring 5(epub)

    Database interaction using Spring and Hibernate/JPA- Spring Data JPA- Spring Data MongoDB- Messaging, emailing and caching support- Spring Web MVC- Developing RESTful web services using Spring Web ...

    Spring cloud和Spring boot介绍

    Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...

    spring 5 中文注释源码.rar

    新版 spring 5 中文注释源码,关键源码位置都有中文注释,方便阅读源码 spring源码解读 Spring框架是由于软件开发的复杂性而创建的...从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

    spring-boot中文教程

    描述:Spring Boot中文文档是Spring Boot官方文档的中文翻译版,它包含了Spring Boot的基本介绍、快速入门、核心特性、高级特性等内容,可以帮助用户快速了解和掌握Spring Boot的使用方法和技巧。 Spring Boot是一款...

    spring 源码中文注释

    spring 源码解析

    SpringBoot+SpringCloud面试题.doc

    Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring boot专注于快速、方便集成的单个个体,Spring Cloud是关注...

    Spring构建微服务实例(Spring、Spring Boot和Spring Cloud),Maven项目

    通过一个使用Spring、Spring Boot和Spring Cloud的小例子来说明如何构建微服务系统。 具体请看附件文件中的:readme.txt 和 [译]Spring构建微服务.png 访问地址:http://localhost:1111/ 运行顺序:...

    Spring Boot中配置文件介绍及其使用教程

    Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置...

    在Spring中使用JTA事务管理

    在Spring中使用JTA事务管理 1 通过集成JOTM,直接在Spring中使用JTA事务 1.1. 将JOTM以下类库添加到类路径中 1.2. 编写JOTM配置文件,放到类路径下 1.3. 在MySQL上建立两个数据库 1.4. 在Spring配置文件中配置JOTM ...

    spring jar 包详解

    (1) spring-core.jar 这个jar文件包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。 (2) spring-beans.jar 这个...

    spring源码分析(1-10)

    Spring源代码解析(一):Spring中的事务处理 Spring源代码解析(二):ioc容器在Web容器中的启动 Spring源代码分析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy ...

    spring2.0中文手册及使用指南 chm

    spring2.0中文手册及使用指南,chm格式

    Learning.Spring.Application.Development.1783987367

    Discover the key Spring framework-related technology standards such as Spring core, Spring-AOP, Spring data access frameworks, and Spring testing to develop robust Java applications easily and rapidly...

    spring-cloud-gateway-server-3.1.1-API文档-中文版.zip

    赠送jar包:spring-cloud-gateway-server-3.1.1.jar; 赠送原API文档:spring-cloud-gateway-server-3.1.1-javadoc.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    Spring boot,springCloud精选视频教程

    3.Spring Cloud中服务的发现与消费 4.Eureka中的核心概念 5.什么是客户端负载均衡 6.Spring RestTemplate中几种常见的请求方式 7.RestTemplate的逆袭之路,从发送请求到负载均衡 8.Spring Cloud中负载均衡器...

    Pro Spring Boot 2第2版-2009-EPUB版

    Pro Spring Boot 2: An Authoritative Guide to Building Microservices, Web and Enterprise Applications, and Best Practices Quickly and productively develop complex Spring applications and microservices...

Global site tag (gtag.js) - Google Analytics