行云无鸣

2012-03-20

Jetty下的struts2报”There is no Action mapped ……”

Filed under: 乱语 — 标签:, , , — hellyguo @ 13:48

在tomcat下正常运行的程序,在jetty下运行异常,报无法找到Struts的ACTION:“There is no Action mapped for namespace / and action name ”。
通过打开struts的devMode,打开struts2的日志和xwork2的日志,终于定位问题:
在web.xml里面指定了struts配置文件struts.xml的路径,写的是“/conf/struts/struts.xml”。这样写,在tomcat下能正常运行,但在jetty下,无法加载,所有配置无法读取到。所以无法找到任何action。改为“conf/struts/struts.xml”就可以了。
总结:jetty的类加载器,比tomcat的加载器要严格。

2012-03-06

为Apache POI启用日志

Filed under: 乱语 — 标签:, , — hellyguo @ 13:10

POI通过JVM参数配置来设置日志类。如果不设置,默认是执行空方法,不输出任何日志。
如果需要POI日志,可设置JVM参数:
-Dorg.apache.poi.util.POILogger=org.apache.poi.util.CommonsLogger
可选的有:

  • CommonsLogger : 采用Apache Common Logging
  • DummyPOILogger : 日志简单放入ArrayList
  • NullLogger : 默认使用的空方法
  • SystemOutLogger : 采用SystemOut输出

选用CommonsLogger,可通过jcl-over-slf4j+slf4j+logback,通过配置logback.xml,灵活输出日志

2011-12-30

高并发下,Double.toString(double)方法存在并发瓶颈

Filed under: 乱语 — 标签:, , , — hellyguo @ 19:51

某项目中使用了大量高精度计算,采用的BigDecimal对象是通过BigDecimal.valueOf(double)或new BigDecimal(Double.toString(double))来生成的。
在高并发下,Double.toString(double)存在互斥锁,将block其他线程。
而由于项目中每个线程几乎都是在计算,导致线程互斥几率大幅放大。

如图1,这是获得锁的线程,“Owns Monitor Lock on sun/misc/FloatingDecimal@0000000116824D10/0000000116824D28”
owns lock thread
如图2,这是等待锁的线程之一,“Waiting for Monitor Lock on sun/misc/FloatingDecimal@0000000116824D10/0000000116824D28”
blocked thread
锁等待的时间倒是都不会太长,在8ms左右。但在高并发情况下,CPU会急剧飙升,且处理时间也会因此而拉长。
blacked time

解决方法:
BigDecimal对象改用new BigDecimal(String)方法来生成,可回避此问题

2011-08-08

Maven管理的项目下加入Mina报错解决

Filed under: 乱语 — 标签:, , , — hellyguo @ 20:11

项目中依赖mina
加入mina后,发现报错:
内容
            <dependency>
                 <groupId>org.apache.mina</groupId>
                 <artifactId>mina-core</artifactId>
                 <version>2.0.2</version>
            </dependency>
            
            <dependency>
                 <groupId>org.apache.mina</groupId>
                 <artifactId>mina-integration-beans</artifactId>
                 <version>2.0.2</version>
            </dependency>
报错信息
11-8-8 下午05时21分27秒: [INFO] Using ‘UTF-8’ encoding to copy filtered resources.
11-8-8 下午05时21分27秒: [INFO] Copying 14 resources
11-8-8 下午05时21分28秒: [INFO] Nothing to compile – all classes are up to date
11-8-8 下午05时21分28秒: [INFO] Using ‘UTF-8’ encoding to copy filtered resources.
11-8-8 下午05时21分28秒: [INFO] Copying 1 resource
11-8-8 下午05时21分43秒: Refreshing [/ecas_dg_under_eracore/pom.xml]
11-8-8 下午05时21分43秒: Missing artifact org.apache.mina:mina-core:bundle:2.0.2:compile
11-8-8 下午05时21分43秒: Missing artifact org.apache.mina:mina-integration-beans:bundle:2.0.2:compile
11-8-8 下午05时21分43秒: Missing artifact org.apache.mina:mina-integration-ognl:bundle:2.0.2:compile
11-8-8 下午05时21分45秒: Maven Builder: AUTO_BUILD
原因
mina打包为了bundle格式,为此,需要添加插件
在maven的pom.xml中plugins段中加入plugin即可
            <plugin>
                  <groupId>org.apache.felix</groupId>
                  <artifactId>maven-bundle-plugin</artifactId>
                  <extensions>true</extensions>
            </plugin>

2011-06-29

自定义Taglib的注意点

Filed under: 乱语 — 标签:, , — hellyguo @ 21:10

如果不采用打包jar模式,直接放置于WEB-INF/classes下即可。然后将tld放置于WEB-INF下即可。jsp申明中uri可直接引用WEB-INF/xxx.tld。
如果采用打包jar模式,需要将tld在jar的META-INF/tlds中放置一份。可引用tld中声明的uri,也可使用WEB-INF/xxx.tld。
jsp 2.0 规范

Jenkins在网络异常情况下不断输出DNS异常信息

Filed under: 乱语 — 标签:, , , , — hellyguo @ 20:51

Jenkins就是被Oracle逼迫改名的Hudson。

这东西用着很顺手。但也有憋屈的时候。

不知道咋地,它需要连接外网。一旦网络不好,无法连接外网,就有好戏看了:

question: [DNSQuestion@9657493 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
question: [DNSQuestion@29482661 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
……
question: [DNSQuestion@30271546 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
question: [DNSQuestion@21587429 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
0: 7642704a64754e6a 6f7976594c487259 6c5852434c426963 7341486b57724676 vBpJduNj oyvYLHrY lXRCLBic sAHkWrFv
20: 525a527a65536c54 6d537970626d586a 427375446b586872 534c735a67465243 RZRzeSlT mSypbmXj BsuDkXhr SLsZgFRC
40: 474b737869736747 424a697249594641 4575426170616770 67636d697a79446d GKsxisgG BJirIYFA EuBapagp gcmizyDm
60: 524f7100 ROq.

2011-6-29 11:59:39 javax.jmdns.impl.constants.DNSRecordClass classForIndex
警告: Could not find record class for index: -1
2011-6-29 11:59:39 javax.jmdns.impl.DNSIncoming$MessageInputStream readName
严重: bad domain name: possible circular name detected. Bad offset: 0xffffffff at 0x62
2011-6-29 11:59:39 javax.jmdns.impl.constants.DNSRecordType typeForIndex
严重: Could not find record type for index: -1
2011-6-29 11:59:39 javax.jmdns.impl.DNSIncoming readQuestion
严重: Could not find record type: dns[query,192.168.10.243:5354, length=100, id=0x7642, flags=0x704a, questions=8779
questions:
[DNSQuestion@10697984 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
……
[DNSQuestion@73029 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
[DNSQuestion@19446204 type: TYPE_UNKNOWN index 0, name: ]
question: [DNSQuestion@10105145 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
……
question: [DNSQuestion@31005306 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
question: [DNSQuestion@12736927 type: TYPE_IGNORE index 0, class: CLASS_UNKNOWN index 0, name: ]
0: 7642704a64754e6a 6f7976594c487259 6c5852434c426963 7341486b57724676 vBpJduNj oyvYLHrY lXRCLBic sAHkWrFv
20: 525a527a65536c54 6d537970626d586a 427375446b586872 534c735a67465243 RZRzeSlT mSypbmXj BsuDkXhr SLsZgFRC
40: 474b737869736747 424a697249594641 4575426170616770 67636d697a79446d GKsxisgG BJirIYFA EuBapagp gcmizyDm
60: 524f7100 ROq.

2011-6-29 12:00:57 javax.jmdns.impl.constants.DNSRecordClass classForIndex
警告: Could not find record class for index: -1
2011-6-29 12:00:57 javax.jmdns.impl.DNSIncoming$MessageInputStream readName
严重: bad domain name: possible circular name detected. Bad offset: 0xffffffff at 0x62
2011-6-29 12:00:57 javax.jmdns.impl.constants.DNSRecordType typeForIndex
严重: Could not find record type for index: -1
2011-6-29 12:00:57 javax.jmdns.impl.constants.DNSRecordClass classForIndex

来看看我被撑爆的硬盘,可怜我D盘就剩下13G+了,都被Jenkins日志吃了

jenkins-out-of-disk

Jenkins将我D盘剩余的13G+空间都吃光了

目前,好像无解……

2010-10-11

JDBC连接报ORA-12505,sid无法找到

Filed under: 乱语 — 标签:, , , , — hellyguo @ 16:24

用JDBC连接ORACLE

jdbc:oracle:thin:@192.168.10.111:1521:ora10g

报错

java.sql.SQLException: Listener refused the connection with the following error:
ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
The Connection descriptor used by the client was:
192.168.10.111:1521:ora10g

用下面这个串就是可以的

jdbc:oracle:oci8:@(description=(address=(host=192.168.10.111)(protocol=tcp)(port=1521))(connect_data=(service_name=ora10g)(server=DEDICATED)))

最后确认,该服务器是RAC,如果单联,需要用

jdbc:oracle:thin:@192.168.10.111:1521:ora10g1

or

jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.111)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.112)(PORT = 1521))(LOAD_BALANCE = yes)(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = ora10g)))

over.

2010-07-05

Linux下java时区设置

Filed under: 乱语 — 标签:, , — hellyguo @ 17:09

方法1:

java -Duser.timezone=Asia/Shanghai xxx

方法2:

export TZ=”Asia/Shanghai”

建议使用方法2,一劳永逸

2010-06-26

采用Spring AOP控制线程的非正常退出

Filed under: 乱语 — 标签:, , , — hellyguo @ 16:58

项目中碰到线程的非正常退出,导致某一块功能缺失,是非常危险的。
虽然可以采用定时刷新线程状态这种方式来处理监控,但总是很累赘。
昨日受到启发,可以采用AOP来控制线程的非异常退出。
基本思路:

  1. 当run方法正常结束时,判断是否是业务或系统主动要求的退出,主动要求的,不再重启;非主动要求的,等待此次退出后重启线程;
  2. 当run方法异常结束时,判断是否有必要重启,有必要,重启;没有必要,不再重启。

方法如下:
Spring配置文件

<bean id="demoThread" parent="singleExecThread">
<property name="target">
<ref local="demoThreadBody" />
</property>
</bean>

<bean id="demoThreadBody" class="CommonSingleThread"
autowire="byName">
<property name="runTarget">
<ref local="demoThreadTarget" />
</property>
<property name="idName" value="demoThread" />
</bean>

<bean id="demoThreadTarget" class="DemoThread"
autowire="byName">
<property name="id" value="0" />
</bean>

<bean id="throwsAdvice"
class="ThrowsFromCommonSingleThreadRunAdvice"></bean>

<bean id="throwsAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref local="throwsAdvice" />
</property>
<property name="mappedName">
<value>run</value>
</property>
</bean>

<bean id="afterAdvice" class="AfterCommonSingleThreadRunAdvice"></bean>

<bean id="afterAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref local="afterAdvice" />
</property>
<property name="mappedName">
<value>run</value>
</property>
</bean>

<bean id="singleExecThread" class="org.springframework.aop.framework.ProxyFactoryBean"
abstract="true">
<property name="proxyInterfaces">
<value>ICommonSingleThread</value>
</property>
<property name="interceptorNames">
<list>
<value>throwsAdvisor</value>
<value>afterAdvisor</value>
</list>
</property>
</bean>

DemoThread

public class DemoThread implements Runnable, Constants {
private int id;

public void setId(int id) {
this.id = id;
}

public void run() {
LOGGER.info("start");
if (id % 2 == 0) {
throw new RuntimeException();
}
LOGGER.info("quit");
}

}

ICommonSingleThread

/**
* 单线程控制接口
* ICommonSingleThread Jun 26, 2010 10:39:06 AM
*
* @author helly
*
*/
public interface ICommonSingleThread extends Runnable {

/**
* 设置线程控制标志
*
* @param active
*/
public abstract void setActive(boolean active);

/**
* 获取线程控制标志
*
*/
public abstract boolean isActive();

/**
* 设置线程执行主体
*
* @param target
*/
public abstract void setRunTarget(Runnable runTarget);

/**
* spring配置文件中唯一id
*
* @param id
*/
public abstract void setIdName(String beanId);

/**
* 获取线程状态
*
* @return
*/
public abstract boolean getThreadState();

/**
* 初始化
*/
public abstract void init();

/**
* 销毁
*/
public abstract void destory();

}

CommonSingleThread

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
* 通用线程线程
* CommonSingleThread Jun 23, 2010 8:57:04 PM
*
* @author helly
*
*/
public class CommonSingleThread implements Runnable, Constants,
ICommonSingleThread, ApplicationContextAware {
// Spring ApplicationContext
protected static ApplicationContext appcontext;
// 对象锁
protected Object lock = new Object();
// 线程控制标志
protected boolean active = true;
// 线程
protected Thread thread;
// 运行实例
protected Runnable runTarget;
// spring代理对象
protected Runnable proxyObject;
// spring配置文件中唯一id
protected String idName;

/**
* 设置线程控制标志
*
* @param active
*/
public void setActive(boolean active) {
synchronized (lock) {
this.active = active;
}
}

/**
* 获取线程控制标志
*
* @return
*/
public boolean isActive() {
return active;
}

/**
* 设置线程执行主体
*
* @param target
*/
public void setRunTarget(Runnable runTarget) {
this.runTarget = runTarget;
}

/**
* spring配置文件中唯一id
*
* @param id
*/
public void setIdName(String idName) {
this.idName = idName;
}

/**
* 获取线程状态
*
* @return
*/
public boolean getThreadState() {
synchronized (lock) {
if (thread == null) {
return false;
} else {
return thread.isAlive();
}
}
}

/**
* 初始化
*/
public void init() {
synchronized (lock) {
// 设置代理对象
if (proxyObject == null) {
setupProxyObject();
}
if (!getThreadState()) {
destory();
active = true;
createNewThreadAndStart();
}
}
}

/**
* 根据idName获取被spring代理过的对象
*/
private void setupProxyObject() {
proxyObject = (Runnable) appcontext.getBean(idName);
}

/**
* 创建新线程
*/
protected void createNewThreadAndStart() {
// 创建线程,Runnable主体必须用代理对象创建
// 原因:如果用内部的runTarget对象创建,无法调用到Advice
// 只有调用proxyObject对象,才能通过AOP调用Advice
thread = new Thread(proxyObject, runTarget.getClass().getSimpleName());
thread.start();
}

/**
* 线程执行体
*/
public void run() {
while (active) {
try {
runTarget();
} catch (Exception e) {
LOGGER.warn(e.getMessage(), e);
throw new RuntimeException(e);
}
break;
}
}

/**
* 执行
*/
protected void runTarget() {
runTarget.run();
}

/**
* 销毁
*/
public void destory() {
synchronized (lock) {
if (thread != null) {
active = false;
while (true) {
try {
thread.join();
active = true;
break;
} catch (InterruptedException e) {
continue;
}
}
}
}
}

/**
* 获取spirng上下文
*
* @param arg0
* @throws BeansException
*/
public void setApplicationContext(ApplicationContext context)
throws BeansException {
if (appcontext == null) {
appcontext = context;
}
}
}

AfterAdvice

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

/**
* CommonSingleThread正常退出善后类
* AfterCommonSingleThreadRunAdvice Jun 26, 2010 10:58:35 AM
*
* @author helly
*
*/
public class AfterCommonSingleThreadRunAdvice implements AfterReturningAdvice,
Constants {

public void afterReturning(Object retValue, Method method, Object[] args,
Object target) throws Throwable {
LOGGER.debug("进入AfterCommonSingleThreadRunAdvice");
// 获取对象
final ICommonSingleThread cst = (ICommonSingleThread) target;
// 获取线程名称
final String thName = Thread.currentThread().getName();
// 校验是否需要重新启动
// 如若active状态为true,需要重启
// 否则,不需要
if (cst.isActive()) {
LOGGER.info("需要重启" + thName);
Runnable runit = new Runnable() {
public void run() {
LOGGER.info("重启" + thName);
// 必须等待
// 原因:要预留时间给原异常线程退出。
// 如若不等待,原线程还存活,init方法无法启动新线程
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
}
// 启动新线程
cst.init();
LOGGER.info("重启" + thName + "完成");
}
};
new Thread(runit, "RestartNormalExitThreadFor:" + thName).start();
}
}

}

ThrowsAdvice

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

/**
* CommonSingleThread异常退出善后类
* ThrowsFromCommonSingleThreadRunAdvice Jun 26, 2010 10:55:18 AM
*
* @author helly
*
*/
public class ThrowsFromCommonSingleThreadRunAdvice implements ThrowsAdvice,
Constants {

/**
* 当异常退出时,进入此方法
*
* @param method
* @param args
* @param target
* @param ex
*/
public void afterThrowing(Method method, Object[] args, Object target,
Exception ex) {
LOGGER.debug("进入ThrowsFromCommonSingleThreadRunAdvice");
// 获取对象
final ICommonSingleThread cst = (ICommonSingleThread) target;
// 获取线程名称
final String thName = Thread.currentThread().getName();
// 校验是否需要重新启动
// 如若active状态为true,需要重启
// 否则,不需要
if (cst.isActive()) {
LOGGER.info("需要重启" + thName);
Runnable runit = new Runnable() {
public void run() {
LOGGER.info("重启" + thName);
// 必须等待
// 原因:要预留时间给原异常线程退出。
// 如若不等待,原线程还存活,init方法无法启动新线程
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
}
// 启动新线程
cst.init();
LOGGER.info("重启" + thName + "完成");
}
};
new Thread(runit, "RestartExceptionExitThreadFor:" + thName).start();
}
}
}

Test

import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class DemoThreadTest {
private ICommonSingleThread th;

@Test
public void test() throws Exception {
th.init();
Thread.sleep(1000l);
}

@BeforeTest
public void beforeTest() {
Log4jLoader.loadLog4j();
SpringLoader.loadSpring();
th = (ICommonSingleThread) SpringLoader.context.getBean("demoThread");
}

}

2010-06-04

Windows2008上运行java产生8小时时差问题原因

Filed under: 乱语 — 标签:, , , , , , — hellyguo @ 14:39

在香港搭建环境时发现Margin系统内部时间与Windows系统时间相差8小时。
初期以为是Windows 2008环境问题,更改注册表后,仍无法解决。
经过本周在测试环境测试重现了此问题。
进一步测试发现,此为1.5.0.07版本不支持高版本Windows导致。
在JDK的更新版本中,已得到修复。
但由于JDK5于2009年10月被sun公司结束支持,故无法再度下载到1.5.0.22版本。
可换用1.6.0.18版本。
在测试环境,JDK6的18子版本测试通过,没有时差问题。

建议将UAT环境上的JDK更新到1.6.0.18。
URL:http://java.sun.com/javase/downloads/widget/jdk6.jsp

同时,建议部门检查其他系统,看是否存在此隐患。(WAS自带JDK为IBM JDK,未涉及。本次主要是涉及SUN JDK和Windows VISTA/Windows 7/Windows Server 2008)

Older Posts »

%d 博主赞过: