因为要和老系统集成zipkin,意外的发现老系统使用的httpClient来发送信息。zipkin的官方demo可都是retstTemplate啊!有的搞头。
在看Demo的时候意外的发现其实其实2.5是支持httpClient的,只有到了spring 3之后才是restTemplate;但是我移植到了struts工程之后发现@Autowired的httpClient返回的是NULL;
原来因为在spring的配置文件中的扫描路径有问题。但是改了路径依然没好,这是怎么回事;后来才发现原来报错的是strturs,strtus在分析spring的配置的时候当然报错了。后来单独设置了spring的servlet,再来定义问题解决。
1 <servlet> 2 <servlet-name>action</servlet-name> 3 <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> 4 <init-param> 5 <param-name>config</param-name> 6 <param-value>/WEB-INF/spring-webmvc-servlet.xml,/WEB-INF/struts-config.xml</param-value> 7 </init-param> 8 <load-on-startup>1</load-on-startup> 9 </servlet>
这样其实在web容器中其实跑的两套servlet,一套是struts一套是spring,剩下的servlet-mapping的事情了,决定那个路径转向那个servlet;每个servlet代表的一套解决方案,比如spring提供的是容器和挑转方案;struts(是struts 1)提供的跳转方案。那么两套方案是否可以结合,我的目标是容器采用spring,跳转采用struts,结合的时候,发生了一些事情。
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/spring-webmvc-servlet.xml]; nested exception is java.lang.IllegalStateException: Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher
但是我的已经是jdk 8的啊。后来看到stackoverflow里面的解释,只能用版本是1.5~1.7;check代码里面只是判断1.5,1.6,1.7,其他版本都被认为是1.4。这是spring里面的一段神判断,其实想想也是有道理,人家写这段代码的时候其实只是到1.7,至于1.8会发生什么无从知晓。
1 static { 2 javaVersion = System.getProperty("java.version"); 3 // version String should look like "1.4.2_10" 4 if (javaVersion.indexOf("1.7.") != -1) { 5 majorJavaVersion = JAVA_17; 6 } 7 else if (javaVersion.indexOf("1.6.") != -1) { 8 majorJavaVersion = JAVA_16; 9 } 10 else if (javaVersion.indexOf("1.5.") != -1) { 11 majorJavaVersion = JAVA_15; 12 } 13 else { 14 // else leave 1.4 as default (it's either 1.4 or unknown) 15 majorJavaVersion = JAVA_14; 16 } 17 }
改了环境变量的路径配置;但是eclipse依然是jdk6,于是关掉elcipse,重启一下,重新读入一下jdk的系统配置;为什么在运行tomcat就不行?因为tomcat环境走的系统的jdk;在elipse里面走的编译是1.6;估计如果是运行其实也是eclipse内部配置;但是tomcat的运行就不行,其实是在eclipse之外跑的。
于是尝试用了eclipse早起的版本,但是本地有的一个Luna版本貌似不是企业版的,没有sServer插件,于是在eclipse里面选择Install New Software...,然后在查询框中输入:
Web、Xml、Java EE and OSGi Enterprise Development
然后根据感觉选择相应的组件即可。
后来换了mars,发现没有Dynamic Web Facts,这次在查询框中输入Web就可以了,根据感觉选就可以了。
为什么在struts的action里面就是注入不了呢?
其实不可能成功,spring来管理对象的时候,对于controller类是通过spring的对象池来创建,注入对象,在·DispatcherServlet处理的时候是从object pool中取出之前已经创建好的那个controller供处理请求;但是现在是struts来管理web请求;它是用他的方式来创建Action(相当于spring的controller),当然即使采用spring的声明也不会获取该对象;
但是我使用
1 WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext(); 2 HttpClient httpClient = (HttpClient)wac.getBean("httpClient");
竟然告诉我httpClient没定义!我修改一下log4j的日志级别看看到底咋回事?但是从日志来看应该没问题;
不行,我觉得应该是当前是struts的上下文,即使能够获得ContextLoader,但是此时其实根本就没有WebApplicationContext;后来我改了一种方式:
1 ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext( 2 new String[] { "applicationContext.xml","spring-webmvc-servlet.xml" }); 3 BeanFactory factory = (BeanFactory) appContext; 4 HttpClient httpClient = (HttpClient)factory.getBean("httpClient"); 5 //appContext.close(); 6 7 return httpClient;
这是在一段单例的对象中获得httpClient;这里有一个注释掉的appContext.close(),因为单例,所以不需要关闭;如果关闭,那么里面AsyncReporter报错,说是已经关闭;所以appContext要保留。这样写终于搞定了,看到zipkin里面有了日志的显示。
虽然讲是sprinig和struts是两套环境,但是其实spring的容器是可以和struts共享的;后来我做了一下测试,在这个工程中配置了spring的servlet-mapping,然后开放了一个类标注为@Controller;发现通过 ContextLoader.getCurrentWebApplicationContext()也是无法获取“httpClient”,但是对象池子这次我特意跟进去,意外的发现对象池里面是有对象的,但是仅限于applicationContext;我其实在web.config里面配置了两个配置文件:spring-webmvc-servlet.xml和applicationContext;但是不知道什么原因只是有application里面出现的对象;后来我把spring-webmvc-servlet.xml里面的bean统一移动到application.xml文件中,发现都有了!这个?难道是spring 2.5的bug吗?我的写法就是最上面那段。
可能是写法有问题,但是不纠结了,而且如果是集中在applicationContext.xml里面定义,struts里面通过ContextLoader.getCurrentWebApplicationContext()也是可以访问到httpClient对象的。
但是现在的问题是:感觉没有了portal端的cr和cs,这是怎么回事?
(未解)
这一天下来,基本调通;我有一点没想通,为什么获取spring对象费了一些周折,但是Filter过滤器非常成功,因为门户的servlet处理,brave成功抓取发送:
下图是brave-hc-client的信息;因为是sr和sc的,是servlet的brave成功捕获。
这是因为web.xml里面的配置内容是tomcat要处理的内容,和框架无关(init-param里面定义的细节内容除外),比如servlet,filter等这些都是被tomcat使用;所以filter其实是被tomcat执行,和spring无关,于是servlet可以被DelegateFilter成功处理;但是到applicationContext.xml之类文件的处理(在web.xml文件<servlet>节点的configLocation中定义的配置文件路径)就是各个框架的servlet有针对性的处理,形成了差异化。或者讲,web.xml里面定义的都是全局性的东西,还没有到分context(上下文)的阶段;到了后面针对bean的处理就是只能是针对具体框架了。