??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲国产av玩弄放荡人妇,亚洲人成电影青青在线播放,国产亚洲精品xxxhttp://m.tkk7.com/niumd/天行健、君子以自强不息 Q地势坤、君子以厚d载物…?/description>zh-cnMon, 12 May 2025 00:42:56 GMTMon, 12 May 2025 00:42:56 GMT60Spring JDBC Framework详解——批量JDBC操作、ORM映射http://m.tkk7.com/niumd/archive/2011/05/10/349965.htmlI白I白Tue, 10 May 2011 13:06:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349965.htmlhttp://m.tkk7.com/niumd/comments/349965.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349965.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349965.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349965.html

作者:niumdQ{载请注明出处Q谢?nbsp;  

发表旉Q?010 q?nbsp;03 ?nbsp;17 ?nbsp; 

原文链接Q?a mce_href="/admin/blogs/618449">http://ari.iteye.com/admin/blogs/618449


一、Spring JDBC 概述

     Spring 提供了一个强有力的模板类JdbcTemplate化JDBC操作QDataSource,JdbcTemplate都可以以Bean的方式定义在想xml配置文gQJdbcTemplate创徏只需注入一个DataSourceQ应用程序Dao层只需要承JdbcDaoSupport, 或者注入JdbcTemplateQ便可以获取JdbcTemplateQJdbcTemplate是一个线E安全的c,多个Dao可以注入一个JdbcTemplateQ?/p>



<!--         Oracle数据?          -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@oracle.devcake.co.uk:1521:INTL"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--  set注入方式获取jdbcTemplate -->
<bean id="customerDao" class="JdbcCustomerDao" >
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注入dataSourceQcustomerDao通过l承JdbcDaoSupport ,使用this.getJdbcTemplate()获取JdbcTemplate   -->
<bean id="customerDao" class="JdbcCustomerDao" >
<property name="dataSource" ref="dataSource"/>
</bean>


然后jdbcTemplate对象注入自定义的Dao、或者承JdbcDaoSupportQ例如:

public class JdbcCustomerDao extends JdbcDaoSupport implements CustomerDao {
}
public class JdbcCustomerDao implements CustomerDao {
private JdbcTemplate jdbcTemplate
public void setJdbcTemplate()JdbcTemplate jdbcTemplate{
this.jdbcTemplate=jdbcTemplate
}
}


二?nbsp;JdbcTemplate 提供以下主要Ҏ化JDBC操作Q?/strong>

2.1、List query(String sql,Ojbect[] args,RowMapper rowMapper)

     说明Q常用的查询Qsql待执行的sql语句Qargs是sql语句的参敎ͼrowMapper负责每一行记录{化ؓjava对象存放在listQƈ最l返回,例如Q?/p>

public List<Book> queryByAuthor(String author) {
String sql = "select * from book where author=?";
Collection c = getJdoTemplate().find(sql,
new Object[] { author },new BookRowMapper());
List<Book> books = new ArrayList<Book>();
books.addAll(c);
return books;
}
class BookRowMapper implements RowMapper{
public Object mapRow(ResultSet res, int index) throws SQLException {
Book book = new Book();
book.setId(rs.getInt("id"));
//省略set
return bookQ?
}
}


   更新、删除、其他查询操作类|举例如下Q详l细节请参考spring apiQ?/p>


//q回gؓ一个长整Ş
public long getAverageAge() {
return getJdbcTemplate().queryForLong("SELECT AVG(age) FROM employee");
}
//q回一个整?
public int getTotalNumberOfEmployees() {
return getJdbcTemplate().queryForInt("SELECT COUNT(0) FROM employees");
}
//更新操作
this.jdbcTemplate.update(
"insert into t_actor (first_name, surname) values (?, ?)",
new Object[] {"Leonor", "Watling"});



 2.2、spring 2.5新功能,另类的jdbc ORMQBeanPropertyRowMapper


      上面我们索时必须实现RowMapperQ将l果集{化ؓjava对象。Spring2.5 化了q一操作Q得我们不必再实现RowMapperQ实现此功能的俩个神奇东东便是:ParameterizedRowMapperQParameterizedBeanPropertyRowMapperQ貌似通过java反射机制实现了将resultset字段映射到java对象Q但是数据表的列必须和java对象的属性对应,没有研究源码Q有点类gapache 的BeanUtilQ不知ؓ何这部分在spring开发参考手册没有,N不是l典?/p>



//使用ParameterizedBeanPropertyRowMapper
@SuppressWarnings({"unchecked"})
public List<Customer> getAll() {
return getJdbcTemplate().query("select * from t_customer", ParameterizedBeanPropertyRowMapper.newInstance(Customer.class));
}
//使用BeanPropertyRowMapper
@SuppressWarnings({"unchecked"})
public List<Customer> getAll() {
return getJdbcTemplate().query("select * from t_customer", new BeanPropertyRowMapper(Customer.class));
}



注意QParameterizedBeanPropertyRowMapper是BeanPropertyRowMapper子类。另外表的字D名U必d实体cȝ成员变量名称一_


2.3、spring之JDBC扚w操作

      jdbcTemplate.batchUpdate(final String[] sql) QAPI解释QIssue multiple SQL updates on a single JDBC Statement using batchingQ翻译过来大致ؓQ解军_个sql的插入、更新、删除操作在一个Statement中。性能一般?/span>

   jdbcTemplate.batchUpdate(String sql, final BatchPreparedStatementSetter pss),cM于JDBC的PreparedStatementQ性能较上着有所提高?/span>

   我们举例说明如何使用Q示例如?

final int count = 2000;
final List<String> firstNames = new ArrayList<String>(count);
final List<String> lastNames = new ArrayList<String>(count);
for (int i = 0; i < count; i++) {
firstNames.add("First Name " + i);
lastNames.add("Last Name " + i);
}
jdbcTemplate.batchUpdate(
"insert into customer (id, first_name, last_name, last_login, comments) values (?, ?, ?, ?, ?)",
new BatchPreparedStatementSetter() {
//为prepared statement讄参数。这个方法将在整个过E中被调用的ơ数
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setLong(1, i + 10);
ps.setString(2, firstNames.get(i));
ps.setString(3, lastNames.get(i));
ps.setNull(4, Types.TIMESTAMP);
ps.setNull(5, Types.CLOB);
}
//q回更新的结果集条数
public int getBatchSize() {
return count;
}
});
}



  BatchSqlUpdatecLSqlUpdate 的子c,适用于插入、删除、更新批量操作,内部使用PreparedStatementQ所以效率很高,扚w语句辑ֈ讑֮的batchSizeQ或者手动调用flush才会执行扚w操作。注意:此类是非U程安全的,必须为每个用者创Z个实例,或者在同一个线E中使用前调用reset?/span>

   下面我们举例说明如何使用BatchSqlUpdateQ来执行扚w操作。示例如下:

class BatchInsert extends BatchSqlUpdate {
private static final String SQL = "insert into t_customer (id, first_name, last_name, last_login, "
+ "comments) values (?, ?, ?, ?, null)";
BatchInsert(DataSource dataSource) {
super(dataSource, SQL);
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.TIMESTAMP));
setBatchSize(10);
}
}


int count = 5000;
for (int i = 0; i < count; i++) {
batchInsert.update(new Object[] { i + 100L, "a" + i, "b" + i, null });
}


 xQspring JDBC主要的应用基本上都简单罗列一番,所有代码均为文章D例,不是很严谨,仅ؓ演示每一U用法,抛砖引玉Q希望有独特见解的拍砖,有问题的h明问题所?谢谢



I白 2011-05-10 21:06 发表评论
]]>
Tomcat6.x目录与server.xml详解http://m.tkk7.com/niumd/archive/2011/05/10/349964.htmlI白I白Tue, 10 May 2011 13:04:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349964.htmlhttp://m.tkk7.com/niumd/comments/349964.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349964.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349964.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349964.html阅读全文

I白 2011-05-10 21:04 发表评论
]]>
目重构之命令模?/title><link>http://m.tkk7.com/niumd/archive/2011/05/10/349962.html</link><dc:creator>I白</dc:creator><author>I白</author><pubDate>Tue, 10 May 2011 13:03:00 GMT</pubDate><guid>http://m.tkk7.com/niumd/archive/2011/05/10/349962.html</guid><wfw:comment>http://m.tkk7.com/niumd/comments/349962.html</wfw:comment><comments>http://m.tkk7.com/niumd/archive/2011/05/10/349962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/niumd/comments/commentRss/349962.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/niumd/services/trackbacks/349962.html</trackback:ping><description><![CDATA[<div style="color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; margin-top: 8px; margin-right: 8px; margin-bottom: 8px; margin-left: 8px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #ffffff; background-position: initial initial; background-repeat: initial initial; "> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">    目中有个业务处理类大小117KQ代?700行,看此cd炚wLQ如今如要增加业务逻辑大约20个吧Q此cd果随着目工程的二期、三期如ơ添加逻辑q早有一天大达到MQ噢、mygod。细心研d人的工作ȝQ发现其中有点可攚w的蛛丝马迹(本h很笨、别W我才发现如何改??/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">     下面我们对业务流E、以及涉及的相关c进行介l,<span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">Msg</span>代表接受到客L的一个消息报文,消息报文l构Q消息头<span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">+</span></span>消息体,消息头参数固定、消息体参数不定Q下面是一个简单的cdQ这只是一个模拟场景,<span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">****Req</span></span>代表各户端请求类Q?span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">***Rsp</span></span>代表q回l客L的参数类。实际比此复杂,为描q问题我们简单摘除几个类介绍Q别问我Zq么设计l承。类?span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">msg</span></span>?span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">msgHead</span></span>是组合关pM许画错了、不当之处请指出Q勿恶语向伤Q?/span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span lang="EN-US"> </span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> <br /> <img src="http://dl.iteye.com/upload/attachment/264052/9e823571-e81c-35d0-a4e5-b5b14b525542.png" mce_src="http://dl.iteye.com/upload/attachment/264052/9e823571-e81c-35d0-a4e5-b5b14b525542.png" alt="" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /><br />  处理hHandlercȝ代码逻辑如下Q?/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <pre name="code" class="java" style="color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; margin-top: 0px; margin-right: 5px; margin-bottom: 5px; margin-left: 15px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #fafafa; background-position: initial initial; background-repeat: initial initial; ">//cM主要Ҏ如下 public void execute(Object object) { Message message = (Message)object; int opcode = message.getOpcode(); int connectId = message.getConnectId(); //消息头已l解析,获取消息体,卛_cd性字节数l? byte[] bytes = message.getBytes(); if (opcode == MsgInfo.ADD_RING) { // 订购彩铃 orderRing(connectId, bytes); } else if (opcode == MsgInfo.PRESENT_RING) { // 赠送彩? presentRing(connectId, bytes); } else if (opcode == MsgInfo.DEL_RING) { // 删除个h铃音 delPersonalRing(connectId, bytes); } //此处省略n个else if } //其他删除、赠送与省略的else if中的处理逻辑与之基本相同 private void orderRing(int connectId, byte[] bytes) { //处理Ҏ分ؓ四步Q具体代码省? //1、解析字节数lؓ订购铃音c? //2、处理订购关p? //3、处理结果封装ؓ订购响应c? //4、发送回客户? } //省略presentRing、delPersonalRing{一pd其他ҎQ所有的处理Ҏ参数相同…… </pre> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">    鉴于此、想C用命令模式改造此c,如果不了解命令模式请阅读相关书籍Q大话设计模式或设计与模式,q里我们仅给出大致的定于与类图?/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">何谓命o模式Q将一个请求封装ؓ一个对象,从而是你可用不同的h对客L参数化,对请求排队或记录日志Q以及支持可撤销的操作?/p> <p class="MsoNormal" mce_style="text-indent: 15.75pt; margin: 0cm 0cm 0pt;" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; text-indent: 15.75pt; "> <span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">Shit</span></span>、这句话很难理解哦,那就先别理解了,我们看下命o模式的类图,然后介绍如何使用命o模式攚w上面的<span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">elseif</span></span>?/p> <p class="MsoNormal" mce_style="text-indent: 21pt; margin: 0cm 0cm 0pt;" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; text-indent: 21pt; ">cd先省略,上班L写的Q?/p> <p class="MsoNormal" mce_style="text-indent: 21pt; margin: 0cm 0cm 0pt;" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; text-indent: 21pt; "><span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; "> </span></span></p> <p class="MsoNormal" mce_style="text-indent: 21pt; margin: 0cm 0cm 0pt;" style="margin-top: 0cm; margin-right: 0cm; margin-bottom: 0pt; margin-left: 0cm; text-indent: 21pt; ">下面q入正题Q对<span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">Handler</span></span>手术开始,主要考虑如下Q?/p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><strong><span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">1?/span></span>提炼Ҏ</strong></p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">     每?span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">if</span></span>语句块中的逻辑提取Z个方法,q里我们?span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">handler</span></span>已经实现Q就是:<span mce_style="font-family: 'Courier New'; color: black; font-size: 10pt;" style="font-family: 'Courier New'; color: black; font-size: 10pt; ">orderRing</span>?span mce_style="font-family: 'Courier New'; color: black; font-size: 10pt;" style="font-family: 'Courier New'; color: black; font-size: 10pt; ">presentRing</span>?span mce_style="font-family: 'Courier New'; color: black; font-size: 10pt;" style="font-family: 'Courier New'; color: black; font-size: 10pt; ">delPersonalRing</span>?#8230;…?/p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><strong><span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">2?/span></span>提炼c?/strong></p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">  每个业务处理方法提取ؓ以各c,然后对具体类q行抽象Q提取父cL者接口;代码如下Q?/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <pre name="code" class="java" style="color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; margin-top: 0px; margin-right: 5px; margin-bottom: 5px; margin-left: 15px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #fafafa; background-position: initial initial; background-repeat: initial initial; ">public Abstract class Command{ public void execute() ? public class OrderRingCommand extends Command { private Handler hander; public OrderRingCommand(Handler hander){ this.hander = hander; } public void execute(int connectId, byte[] bytes){ //1、解析字节数lؓ订购铃音c? //2、增加订购关p? //3、处理结果封装ؓ订购响应c? //4、发送回客户? } /** * 1、解析字节数lؓ订购铃音c? */ public void method1(){ } /** * 2、处理订购关p? */ public void method2(){ } /** * 3、处理结果封装ؓ订购响应c? */ public void method3(){ } /** * 4、结果发送回客户? */ public void method4(){ } } public class DelRingCommand extends Command { private Handler hander; public DelRingCommand(Handler hander){ this.hander = hander; } public void execute(int connectId, byte[] bytes){ //1、解析字节数lؓ订购铃音c? //2、删除购关系 //3、处理结果封装ؓ订购响应c? //4、发送回客户? } //提取Ҏ } </pre> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> <span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "> </span></span></span></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><strong><span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; ">3?/span></span>命o模式攚w替?/strong><span lang="EN-US"><span mce_style="font-family: Calibri;" style="font-family: Calibri; "><strong>elseifQ?/strong></span></span></p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <pre name="code" class="java" style="color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; margin-top: 0px; margin-right: 5px; margin-bottom: 5px; margin-left: 15px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #fafafa; background-position: initial initial; background-repeat: initial initial; ">Map<Integer, Command> map = new HashMap<Integer,Command>(); static{ map.put(MsgInfo.ADD_RING, new OrderRingCommand()); //省却其他Q这里仅为演C,实际目中实例化c通过spring容器或者其他方? } public void execute(Object object) { Message message = (Message)object; int opcode = message.getOpcode(); int connectId = message.getConnectId(); //消息头已l解析,获取消息体,卛_cd性字节数l? byte[] bytes = message.getBytes(); map.get(opcode).execute(connectId,bytes); } </pre> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "></span></span></span></span></span></span></span></span></span></span></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">     <span lang="EN-US"></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "></span></span></span></span></span></span></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span lang="EN-US"></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span lang="EN-US"> 命o模式替换else if代码坏味道的重构l束Q众多的if条g块烟消云散,取而代之的是一个个_的类Qdoc版本在附件中</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span lang="EN-US"><font><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><font mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "></font></span></span></span></span></span></span></font></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><font><font mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><br /> </font></font></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "><span mce_style="font-size: 10.5pt;" style="font-size: 10.5pt; "></span></span></span></span></span></span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p class="MsoListParagraph" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><br /> </p> </div> <img src ="http://m.tkk7.com/niumd/aggbug/349962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/niumd/" target="_blank">I白</a> 2011-05-10 21:03 <a href="http://m.tkk7.com/niumd/archive/2011/05/10/349962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入出ThreadLocalhttp://m.tkk7.com/niumd/archive/2011/05/10/349961.htmlI白I白Tue, 10 May 2011 13:02:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349961.htmlhttp://m.tkk7.com/niumd/comments/349961.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349961.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349961.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349961.html

一、ThreadLocal概述

       学习JDK中的c,首先看下JDK APIҎcȝ描述Q描q如下:

JDK API 写道
该类提供了线E局?(thread-local) 变量。这些变量不同于它们的普通对应物Q因问某个变量(通过?get ?set ҎQ的每个U程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段Q它们希望将状态与某一个线E(例如Q用?ID 或事?IDQ相兌?nbsp;

    API表达了下面几U观点:

1、ThreadLocal不是U程Q是U程的一个变量,你可以先单理解ؓU程cȝ属性变量?/p>

2、ThreadLocal 在类中通常定义为静态类变量?/p>

3、每个线E有自己的一个ThreadLocalQ它是变量的一?#8216;拯’Q修改它不媄响其他线E?/p>


    既然定义为类变量Qؓ何ؓ每个U程l护一个副本(姑且成ؓ‘拯’Ҏ理解Q,让每个线E独立访问?多线E编E的l验告诉我们Q对于线E共享资源(你可以理解ؓ属性)Q资源是否被所有线E共享,也就是说q个资源被一个线E修Ҏ否媄响另一个线E的q行Q如果媄响我们需要用synchronized同步Q让U程序讉K?/p>


   ThreadLocal适用于资源共享但不需要维护状态的情况Q也是一个线E对资源的修改,不媄响另一个线E的q行Q这U设计是‘I间换时?#8217;Qsynchronized序执行?strong>‘旉换取I间’?/p>


二、ThreadLocalҎ介绍



 T get() 
          q回此线E局部变量的当前U程副本中的倹{?/td>
protected  T initialValue() 
          q回此线E局部变量的当前U程?#8220;初始?#8221;?/td>
 void remove() 
          U除此线E局部变量当前线E的倹{?/td>
 void set(T value) 
          此U程局部变量的当前U程副本中的D|ؓ指定倹{?/td>


三、深入源?/strong>

    ThreadLocal有一个ThreadLocalMap静态内部类Q你可以单理解ؓ一个MAPQ这?#8216;Map’为每个线E复制一个变量的‘拯’存储其中?/p>

    当线E调用ThreadLocal.get()Ҏ获取变量?首先获取当前U程引用Q以此ؓkey去获取响应的ThreadLocalMapQ如果此‘Map’不存在则初始化一个,否则q回其中的变量,代码如下Q?/p>


 public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}

    调用getҎ如果此Map不存在首先初始化Q创建此mapQ将U程为keyQ初始化的vlaue存入其中Q注意此处的initialValueQ我们可以覆盖此ҎQ在首次调用时初始化一个适当的倹{setInitialValue代码如下Q?/p>

    private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}


    setҎ相对比较单如果理解以上俩个方法,获取当前U程的引用,从map中获取该U程对应的mapQ如果map存在更新~存|否则创徏q存储,代码如下Q?/p>

    public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}


    对于ThreadLocal在何处存储变量副本,我们看getMapҎQ获取的是当前线E的ThreadLocalcd的threadLocals属性。显然变量副本存储在每一个线E中?/p>


/**
* 获取U程的ThreadLocalMap 属性实?
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}


    上面我们知道变量副本存放于何处,q里我们单说下如何被java的垃圾收集机制收集,当我们不在用是调用set(null)Q此时不在将引用指向?#8216;map’Q而线E退出时会执行资源回收操作,申L资源q行回收Q其实就是将属性的引用讄为null。这时已l不在有M引用指向该mapQ故而会被垃圾收集?/p>


 四、ThreadLocal应用CZ


      在我的另一文章,对ThreadLocal的用做了一个实例,此示例也可以用作生环境Q请参见Q?a mce_href="/blog/757641">http://ari.iteye.com/blog/757641



如有问题La讨论Q谢?/p>

I白 2011-05-10 21:02 发表评论
]]>
ThreadLocalCZhttp://m.tkk7.com/niumd/archive/2011/05/10/349960.htmlI白I白Tue, 10 May 2011 13:01:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349960.htmlhttp://m.tkk7.com/niumd/comments/349960.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349960.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349960.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349960.html

    本文借花献佛Q引用Tim Cull的博?#8220;SimpleDateFormat: Performance Pig”介绍下ThreadLocal的简单用,同时也对SimpleDateFormat的用有个深入的了解?/p>

Tim Cull 写道
Just yesterday I came across this problem “in the wild” for the third time in my career so far: an application with performance problems creating tons of java.text.SimpleDateFormat instances. So, I have to get this out there: creating a new instance of SimpleDateFormat is incredibly expensive and should be minimized. In the case that prompted this post, I was using JProfiler to profile this code that parses a CSV file and discovered that 50% of the time it took to suck in the file and make 55,000 objects out of it was spent solely in the constructor of SimpleDateFormat. It created and then threw away a new one every time it had to parse a date. Whew! 

“Great,” you think, “I’ll just create one, static instance, slap it in a field in a DateUtils helper class and life will be good.” 

Well, more precisely, life will be good about 97% of the time. A few days after you roll that code into production you’ll discover the second cool fact that’s good to know: SimpleDateFormat is not thread safe. Your code will work just fine most of the time and all of your regression tests will probably pass, but once your system gets under a production load you’ll see the occasional exception. 

“Fine,” you think, “I’ll just slap a ’synchronized’ around my use of that one, static instance.” 

Ok, fine, you could do that and you’d be more or less ok, but the problem is that you’ve now taken a very common operation (date formatting and parsing) and crammed all of your otherwise-lovely, super-parallel application through a single pipe to get it done.


     大致意思:Tim Cull到一个SimpleDateFormat带来的严重的性能问题Q该问题主要有SimpleDateFormat引发Q创Z个SimpleDateFormat实例的开销比较昂贵Q解析字W串旉旉J创建生命周期短暂的实例D性能低下。即使将SimpleDateFormat定义为静态类变量Q貌D解决q个问题Q但是SimpleDateFormat是非U程安全的,同样存在问题Q如果用‘synchronized’U程同步同样面问题Q同步导致性能下降Q线E之间序列化的获取SimpleDateFormat实例Q?/p>

    Tim Cull使用Threadlocal解决了此问题Q对于每个线ESimpleDateFormat不存在媄响他们之间协作的状态,为每个线E创Z个SimpleDateFormat变量的拷贝或者叫做副本,代码如下Q?/p>


import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 使用ThreadLocal以空间换旉解决SimpleDateFormatU程安全问题?
* @author
*
*/
public class DateUtil {
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
@SuppressWarnings("rawtypes")
private static ThreadLocal threadLocal = new ThreadLocal() {
protected synchronized Object initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
public static DateFormat getDateFormat() {
return (DateFormat) threadLocal.get();
}
public static Date parse(String textDate) throws ParseException {
return getDateFormat().parse(textDate);
}
}


   创徏一个ThreadLocalcd量,q里创徏时用了一个匿名类Q覆盖了initialValueҎQ主要作用是创徏时初始化实例。也可以采用下面方式创徏Q?/p>


//W一ơ调用get返回null
private static ThreadLocal threadLocal = new ThreadLocal()Q?
//获取U程的变量副本,如果不覆盖initialValueQ第一ơgetq回nullQ故需要初始化一个SimpleDateFormatQƈset到threadLocal?
public static DateFormat getDateFormat()
{
DateFormat df = (DateFormat) threadLocal.get();
if(df==null){
df = new SimpleDateFormat(DATE_FORMAT)
threadLocal.set(df);
}
return df;
}


   我们看下我们覆盖的initialValueҎQ?/p>


protected T initialValue() {
return null;//直接q回null
}






I白 2011-05-10 21:01 发表评论
]]>
探究Struts2q行机制QStrutsPrepareAndExecuteFilter 源码剖析http://m.tkk7.com/niumd/archive/2011/05/10/349959.htmlI白I白Tue, 10 May 2011 12:58:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349959.htmlhttp://m.tkk7.com/niumd/comments/349959.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349959.html#Feedback4http://m.tkk7.com/niumd/comments/commentRss/349959.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349959.html

  作者:niumd

  blogQ?a mce_href="/">http://ari.iteye.com

 一、概q?/strong>

     Struts2的核心是一个FilterQAction可以qweb容器Q那么是什么让httph和action兌在一LQ下面我们深入源码来分析下Struts2是如何工作的?/p>

FilterDispatcher API 写道
Deprecated. Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one


     鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcherQ我们此文将剖析StrutsPrepareAndExecuteFilterQ其在工E中作ؓ一个Filter配置在web.xml中,配置如下Q?/p>

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


二、源码属性方法简?/strong>

    下面我们研究下StrutsPrepareAndExecuteFilter源码Q类的主要信息如下:


属性摘?/strong>
protected  List<Pattern> excludedPatterns 
           
protected  ExecuteOperations execute 
           
protected  PrepareOperations prepare 
           


    StrutsPrepareAndExecuteFilter与普通的Filterq无区别Q方法除l承自Filter外,仅有一个回调方法,W三部分我们按照FilterҎ调用序Q由init?gt;doFilter?gt;destroy序地分析源码?/p>
Ҏ摘要
 void destroy() 
           l承自FilterQ用于资源释?/td>
 void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
           l承自FilterQ执行方?/td>
 void init(FilterConfig filterConfig) 
           l承自FilterQ初始化参数
protected  void postInit(Dispatcher dispatcher, FilterConfig filterConfig) 
          Callback for post initializationQ一个空的方法,用于Ҏ回调初始化)


三、源码剖?nbsp;   


    1、initҎ

         init是FilterW一个运行的ҎQ我们看下struts2的核心Filter在调用initҎ初始化时做哪些工作:

 public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
try {
//装filterConfigQ其中有个主要方法getInitParameterNames参数名字以String格式存储在List?
FilterHostConfig config = new FilterHostConfig(filterConfig);
// 初始化struts内部日志
init.initLogging(config);
//创徏dispatcher Qƈ初始化,q部分下面我们重点分析,初始化时加蝲那些资源
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
//初始化类属性:prepare 、execute
prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
//回调I的postInitҎ
postInit(dispatcher, filterConfig);
} finally {
init.cleanup();
}
}


   首先看下FilterHostConfig Q源码如下:


public class FilterHostConfig implements HostConfig {
private FilterConfig config;
/**
*构造函?
*/
public FilterHostConfig(FilterConfig config) {
this.config = config;
}
/**
*  Ҏinit-param配置的param-name获取param-value的?
*/
public String getInitParameter(String key) {
return config.getInitParameter(key);
}
/**
*  q回初始化参数名的List
*/
public Iterator<String> getInitParameterNames() {
return MakeIterator.convert(config.getInitParameterNames());
}
public ServletContext getServletContext() {
return config.getServletContext();
}
}

   只有短短的几行代码,getInitParameterNames是这个类的核心,Filter初始化参数名U有枚Dcd转ؓIterator。此cȝ主要作ؓ是对filterConfig 装?/p>



    重点来了Q创建ƈ初始化Dispatcher     

 public Dispatcher initDispatcher( HostConfig filterConfig ) {
Dispatcher dispatcher = createDispatcher(filterConfig);
dispatcher.init();
return dispatcher;
}

     创徏DispatcherQ会d filterConfig 中的配置信息Q将配置信息解析出来Q封装成Z个MapQ然后根lservlet上下文和参数Map构造Dispatcher Q?/p>

private Dispatcher createDispatcher( HostConfig filterConfig ) {
Map<String, String> params = new HashMap<String, String>();
for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
String name = (String) e.next();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return new Dispatcher(filterConfig.getServletContext(), params);
}

  Dispatcher初始化,加蝲struts2的相关配|文Ӟ按照顺序逐一加蝲Qdefault.propertiesQstruts-default.xml,struts-plugin.xml,struts.xmlQ?#8230;…


/**
*初始化过E中依次加蝲如下配置文g
*/
public void init() {
if (configurationManager == null) {
configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
try {
//加蝲org/apache/struts2/default.properties
init_DefaultProperties(); // [1]
//加蝲struts-default.xml,struts-plugin.xml,struts.xml
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
//用户自己实现的ConfigurationProvidersc?
init_CustomConfigurationProviders(); // [5]
//Filter的初始化参数
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]
Container container = init_PreloadConfiguration();
container.inject(this);
init_CheckConfigurationReloading(container);
init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled())
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}


   初始化default.propertiesQ具体的初始化操作在DefaultPropertiesProvidercM

  

 private void init_DefaultProperties() {
configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
}

    

   下面我们看下DefaultPropertiesProvidercL码:


public void register(ContainerBuilder builder, LocatableProperties props)
throws ConfigurationException {
Settings defaultSettings = null;
try {
defaultSettings = new PropertiesSettings("org/apache/struts2/default");
} catch (Exception e) {
throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);
}
loadSettings(props, defaultSettings);
}


   其他的我们再ơ省略,大家可以览下各个初始化操作都加载了那些文g


3、doFilterҎ

     doFilter是过滤器的执行方法,它拦截提交的HttpServletRequesthQHttpServletResponse响应Q作为strtus2的核心拦截器Q在doFilter里面到底做了哪些工作Q我们将逐行解读其源码,源码如下Q?/p>


    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
//父类向子c{Q强转ؓhttph、响?
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
//讄~码和国际化
prepare.setEncodingAndLocale(request, response);
//创徏Action上下文(重点Q?
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}


    setEncodingAndLocale调用了dispatcherҎ的prepareҎQ?/p>


/**
* Sets the request encoding and locale on the response
*/
public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {
dispatcher.prepare(request, response);
}


   下面我们看下prepareҎQ这个方法很单只是设|了encoding 、locale Q做的只是一些辅助的工作Q?/p>

public void prepare(HttpServletRequest request, HttpServletResponse response) {
String encoding = null;
if (defaultEncoding != null) {
encoding = defaultEncoding;
}
Locale locale = null;
if (defaultLocale != null) {
locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
}
if (encoding != null) {
try {
request.setCharacterEncoding(encoding);
} catch (Exception e) {
LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
}
}
if (locale != null) {
response.setLocale(locale);
}
if (paramsWorkaroundEnabled) {
request.getParameter("foo"); // simply read any parameter (existing or not) to "prime" the request
}
}


   Action上下文创建(重点Q?/strong>

       ActionContext是一个容器,q个Ҏ主要存储request、session、application、parameters{相关信?ActionContext是一个线E的本地变量Q这意味着不同的action之间不会׃nActionContextQ所以也不用考虑U程安全问题。其实质是一个MapQkey是标Crequest、session?#8230;…的字W串Q值是其对应的对象Q?/p>

static ThreadLocal actionContext = new ThreadLocal();
Map<String, Object> context;

 
   下面我们看下如何创徏action上下文的Q代码如下:


/**
*创徏Action上下文,初始化thread local
*/
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
//注意此处是从ThreadLocal中获取此ActionContext变量
ActionContext oldContext = ActionContext.getContext();
if (oldContext != null) {
// detected existing context, so we are probably in a forward
ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
} else {
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
//stack.getContext()q回的是一个Map<StringQObject>Q根据此Map构造一个ActionContext
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
//ActionContext存如ThreadLocal
ActionContext.setContext(ctx);
return ctx;
}


    上面代码中dispatcher.createContextMapQ如何封装相兛_敎ͼ


public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping, ServletContext context) {
// request map wrapping the http request objects
Map requestMap = new RequestMap(request);
// parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately
Map params = new HashMap(request.getParameterMap());
// session map wrapping the http session
Map session = new SessionMap(request);
// application map wrapping the ServletContext
Map application = new ApplicationMap(context);
//requestMap、params、session{Map装成ؓ一个上下文MapQ逐个调用了map.put(Map p).
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
if (mapping != null) {
extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
}
return extraContext;
}


 我们单看下RequestMapQ其他的省略。RequestMapcdC抽象MapQ故其本w是一个MapQ主要方法实玎ͼ

//map的get实现
public Object get(Object key) {
return request.getAttribute(key.toString());
}
//map的put实现
public Object put(Object key, Object value) {
Object oldValue = get(key);
entries = null;
request.setAttribute(key.toString(), value);
return oldValue;
}


   下面是源码展CZ如何执行Action控制器:


public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
dispatcher.serviceAction(request, response, servletContext, mapping);
}
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws ServletException {
//装执行的上下文环境Q主要讲相关信息存储入map
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
//获取命名I间
String namespace = mapping.getNamespace();
//获取action配置的name属?
String name = mapping.getName();
//获取action配置的method属?
String method = mapping.getMethod();
Configuration config = configurationManager.getConfiguration();
//Ҏ执行上下文参敎ͼ命名I间Q名U等创徏用户自定义Action的代理对?
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
// if the ActionMapping says to go straight to a result, do it!
//执行executeҎQƈ转向l果
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
// If there was a previous value stack then set it back onto the request
if (!nullStack) {
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
}
} catch (ConfigurationException e) {
// WW-2874 Only log error if in devMode
if(devMode) {
String reqStr = request.getRequestURI();
if (request.getQueryString() != null) {
reqStr = reqStr + "?" + request.getQueryString();
}
LOG.error("Could not find action or result\n" + reqStr, e);
}
else {
LOG.warn("Could not find action or result", e);
}
sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} finally {
UtilTimerStack.pop(timerKey);
}
}


   文中对如何解析Struts.xmlQ如何将URL与action映射匚w为分析,有需要的我后l补全,因ؓStrutsXmlConfigurationProviderl承XmlConfigurationProviderQƈ在registerҎ回调父类的registerQ有兴趣的可以深入阅M下XmlConfigurationProvider源码Q?/p>


 public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
if (servletContext != null && !containerBuilder.contains(ServletContext.class)) {
containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() {
public ServletContext create(Context context) throws Exception {
return servletContext;
}
});
}
//调用父类的registerQ关键点所?
super.register(containerBuilder, props);
}



     struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:

<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>
<!ATTLIST action
name CDATA #REQUIRED
class CDATA #IMPLIED
method CDATA #IMPLIED
converter CDATA #IMPLIED
>

    从上qDTD中可见Action元素可以含有name 、class 、method 、converter 属性?/p>


   XmlConfigurationProvider解析struts.xml配置的Action元素Q?/p>

   protected void addAction(Element actionElement, PackageConfig.Builder packageContext) throws ConfigurationException {
String name = actionElement.getAttribute("name");
String className = actionElement.getAttribute("class");
String methodName = actionElement.getAttribute("method");
Location location = DomHelper.getLocationObject(actionElement);
if (location == null) {
LOG.warn("location null for " + className);
}
//methodName should be null if it's not set
methodName = (methodName.trim().length() > 0) ? methodName.trim() : null;
// if there isnt a class name specified for an <action/> then try to
// use the default-class-ref from the <package/>
if (StringUtils.isEmpty(className)) {
// if there is a package default-class-ref use that, otherwise use action support
/* if (StringUtils.isNotEmpty(packageContext.getDefaultClassRef())) {
className = packageContext.getDefaultClassRef();
} else {
className = ActionSupport.class.getName();
}*/
} else {
if (!verifyAction(className, name, location)) {
if (LOG.isErrorEnabled())
LOG.error("Unable to verify action [#0] with class [#1], from [#2]", name, className, location.toString());
return;
}
}
Map<String, ResultConfig> results;
try {
results = buildResults(actionElement, packageContext);
} catch (ConfigurationException e) {
throw new ConfigurationException("Error building results for action " + name + " in namespace " + packageContext.getNamespace(), e, actionElement);
}
List<InterceptorMapping> interceptorList = buildInterceptorList(actionElement, packageContext);
List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(actionElement, packageContext);
ActionConfig actionConfig = new ActionConfig.Builder(packageContext.getName(), name, className)
.methodName(methodName)
.addResultConfigs(results)
.addInterceptors(interceptorList)
.addExceptionMappings(exceptionMappings)
.addParams(XmlHelper.getParams(actionElement))
.location(location)
.build();
packageContext.addActionConfig(name, actionConfig);
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded " + (StringUtils.isNotEmpty(packageContext.getNamespace()) ? (packageContext.getNamespace() + "/") : "") + name + " in '" + packageContext.getName() + "' package:" + actionConfig);
}
}



     工作中不涉及Struts2Q本周工作有?天的I档期,E微看了下struts2的文档,写了个demoQ从源码的角度研I了下运行原理,如有分析不当h出,我后l逐步完善更正Q大家共同提高?/p>




I白 2011-05-10 20:58 发表评论
]]>
Nginx+tomcat配置集群负蝲均衡http://m.tkk7.com/niumd/archive/2011/05/10/349958.htmlI白I白Tue, 10 May 2011 12:56:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349958.htmlhttp://m.tkk7.com/niumd/comments/349958.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349958.html#Feedback5http://m.tkk7.com/niumd/comments/commentRss/349958.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349958.html

  作者:niumd 

  Blog:http://ari.iteye.com

  转蝲h明出处,谢谢


    开发的应用采用F5负蝲均衡交换机,F5请求{发给5台hp unix服务器,每台服务器有多个webserver实例Q对外提供web服务和socket{接口服务。之初,曾有个小的疑问Z不采用开源的apache、Nginx软g负蝲QF5讑֤动辄几十万,h昂贵Q自׃个比较幼E的问题Q后l明白:F5是操作于IOS|络模型的传输层QNginx、apache是基于http反向代理方式Q位于ISO模型的第七层应用层。直白些是TCP UDP 和http协议的区别,Nginx不能为基于TCP协议的应用提供负载均衡?/p>


      了解了二者之间的区别于应用场景,对Nginx产生厚的兴,阅读张宴?lt;实战Nginx>Q这?5q的伙子年L为M?妒忌Q,搞明白了大致原理和配|,Ubuntu10.10Qwindow下对Nginx+tomcat负蝲均衡做了配置试Q将全部h转发到tomcatQƈ未做静态,动态分开Q图片防盗链{配|?br /> Nginx 介绍


     Nginx Q发韛_ engine xQ是一ƾ轻量的Web 服务器/反向代理服务器及电子邮gQIMAP/POP3Q代理服务器Qƈ在一个BSD-like 协议下发行?nbsp; 其特Ҏ占有内存,q发能力强,事实上nginx的ƈ发能力确实在同类型的|页伺服器中表现较好.目前中国大陆使用nginx|站用户有:新浪、网易?腾讯,另外知名的微|志Plurk也用nginx?/p>


    上面的全是Nginx介绍基本上是废话Q下面{入正题,图文l合展示基本配置Q首先是window环境、其ơ是Ubuntu环境QVbox虚拟Q。本文主要基于Nginx下配|两台tomcatQ结构如下图Q?br />
 

Window xp环境QNginx+Tomcat6

1、下载地址

       http://nginx.org/en/download.html Q这里我们推荐下载稳定版Qstable versionsQ,本文采用nginx-0.8.20?/p>


2、目录结?/strong>


      Nginx-

               |_  conf   配置目录

               |_  contrib

               |_  docs 文档目录

               |_  logs  日志目录

               |_  temp 临时文g目录

               |_  html 静态页面目?/p>

               |_  nginx.exe ȝ?/p>


      window下安装Nginx极其单,解压~到一个无I格的英文目录即可(个h习惯Q担心中文出问题Q,双击nginx启动Q这里我安装刎ͼD:\server目录Q下面涉及到的tomcat也安装在此目录?/p>

   

DOS环境启动

 

若果惛_止nginxQdos环境q行命oQnginx -s stop


3、nginx.conf配置


   Nginx配置文g默认在conf目录Q主要配|文件ؓnginx.confQ我们安装在D:\server\nginx-0.8.20、默认主配置文g为D:\server\nginx-0.8.20\nginx.conf。下面是nginx作ؓ前端反向代理服务器的配置?/p>

#Nginx所用用户和l,window下不指定
#user  niumd niumd;
#工作的子q程数量Q通常{于CPU数量或?倍于CPUQ?
worker_processes  2;
#错误日志存放路径
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  logs/error.log  info;
#指定pid存放文g
pid        logs/nginx.pid;
events {
#使用|络IO模型linuxepollQFreeBSD采用kqueueQwindow下不指定?
#use epoll;
#允许最大连接数
worker_connections  2048;
}
http {
include       mime.types;
default_type  application/octet-stream;
#定义日志格式
#log_format  main  '$remote_addr - $remote_user [$time_local] $request '
#                  '"$status" $body_bytes_sent "$http_referer" '
#                  '"$http_user_agent" "$http_x_forwarded_for"';
#access_log  off;
access_log  logs/access.log;
client_header_timeout  3m;
client_body_timeout    3m;
send_timeout           3m;
client_header_buffer_size    1k;
large_client_header_buffers  4 4k;
sendfile        on;
tcp_nopush      on;
tcp_nodelay     on;
#keepalive_timeout  75 20;
include    gzip.conf;
upstream localhost {
#Ҏip计算请求分配各那个后端tomcatQ许多h误认为可以解决session问题Q其实ƈ不能?
#同一机器在多|情况下Q\由切换,ip可能不同
#ip_hash;
server localhost:18081;
server localhost:18080;
}
server {
listen       80;
server_name  localhost;
location / {
proxy_connect_timeout   3;
proxy_send_timeout      30;
proxy_read_timeout      30;
proxy_pass http://localhost;
}
}
}

 
   代理讄如下Q?/p>

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   300;
proxy_send_timeout      300;
proxy_read_timeout      300;
proxy_buffer_size       4k;
proxy_buffers           4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;


   gzip压羃相关配置如下Q?/p>

gzip              on;
gzip_min_length      1000;
gzip_types         text/plain text/css application/x-javascript;

 
  4、Tomcat配置


   对于tomcat大家都很熟悉Q只需要修改server.xml配置文g卛_Q这里我们以apache-tomcat-6.0.14ZQ分别在server目录Q解压羃q命名ؓQapache-tomcat-6.0.14_1、apache-tomcat-6.0.14_2?/p>


    W一处端口修改:

<!--  修改port端口Q?8006 俩个tomcat不能重复Q端口随意,别太?->
<Server port="18006" shutdown="SHUTDOWN">

 
   W二处端口修改:

<!-- port="18081" tomcat监听端口Q随意设|,别太?-->
<Connector port="18081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
 


   W三处端口修改:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />


   Engine元素增加jvmRoute属性:

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">

 
    两个tomcat的端口别重复Q保证能启动hQ另一个tomcat配置希捷省略Q监听端口ؓ18080Q附件中我们上传所有的配置信息?/p>


5、验证配|与试负蝲均衡


    首先试nginx配置是否正确Q测试命令:nginx -t  (默认验证:conf\nginx.conf),也可以指定配|文件\径?/p>

 此例nginx安装目录QD:\server\nginx-0.8.20Qdos环境下图画面成功CZQ?br />

   其次验证tomcatQ启动两个tomcatQ不出现端口冲突即ؓ成功Qtomcat依赖的java{搞“挨踢”的就废话不说了)Q?/p>

 

    最后验证配|负载均衡设|,http://localhost/ ?a href="http://localhost/index.jsp" mce_href="http://localhost/index.jsp">http://localhost/index.jsp 。我修改了index.jsp面Q增加日志输Z息,便于观察。注意:左上角小猫头上的Qaccess tomcat2、access tomcat1。说明访问了不同的tomcat?/p>

  

 
     xwindow下nginx+tomcat负蝲均衡配置l束Q关于tomcat Session的问题通常是采用memcachedQ或者采用nginx_upstream_jvm_route Q他是一?Nginx 的扩展模块,用来实现Z Cookie ?Session Sticky 的功能。如果tomcatq多不徏议session同步Qserver间相互同步session很耗资源,高ƈ发环境容易引起Session风暴。请Ҏ自己应用情况合理采纳session解决Ҏ?/p>



 作者:niumd 

  Blog:http://ari.iteye.com



Ubuntu10.10环境QNginx+Tomcat6


我们下面单说下ubuntu10.10下如何安装配|,主要以图片ؓ主,单解释?/p>

1、下载Nginx

      地址Q?a mce_>http://nginx.org/en/download.html Qlinux版本Qnginx-0.8.20.tar.。解压羃命oQ?/p>


tar -zxvf nginx-0.8.20.tar.gz


2、编译安装Nginx


     Nginx依赖一些其他PCRE、opensslQ依赖libssl-devQ,本hW记本Ubuntu环境已经安装PCREQ仅需安装依赖的opensslQ下面我们简单说下如何安装PCRE和openssl{?/p>


     PCRE下蝲地址Q?a href="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/" mce_href="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/">ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/


tar zxvf  pcre-8.01.tar.gz
cd pcre-8.01
sudo ./configure
sodu make
sodu make install


    openssl通过apt-get install安装Q命令、截囑֦下:

sudo apt-get install openssl
sudo apt-get install libssl-dev
//如缺其他包Q请采用此方法安装,ubuntu有依赖提C?

 

 
 依赖的Y件包安装完毕Q下面来~译NginxQ?/p>

#window׃n目录软g拯到当前工作目?
cp /mnt/fileshare/nginx-0.8.20.tar.gz ./
#解压~Y件包
tar zxvf nginx-0.8.20.tar.gz
cd nginx-0.8.20
//~译源码,默认使用nobodyQ指定本机已存在的用Pl,启用nginx-status功能Q监控nginx状态。启动debug
sudo ./configure  --user=niumd --group=niumd --with-debug --with-http_stub_status_module
sudo make
sudo make install

 
   截图 如下Q?br />

安装l果截图如下Q?/p>

 

~译安装正确l束Q按照上qwindow下方法检查默认配|,然后在默认配|下启动nginxQ访?a mce_>http://127.0.0.1 Q如下图说明成功

 

Nginx配置成功后我们对window下nginx.conf做修改Q如下:

#Nginx所用用户和l?
user  niumd niumd;
#工作的子q程数量Q通常{于CPU数量或?倍于CPUQ?
worker_processes  2;
#错误日志存放路径
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  logs/error.log  info;
#指定pid存放文g
pid        logs/nginx.pid;
events {
#使用|络IO模型linuxepollQFreeBSD采用kqueue
use epoll;
#允许最大连接数
worker_connections  2048;
}
http {
include       mime.types;
default_type  application/octet-stream;
#定义日志格式
#log_format  main  '$remote_addr - $remote_user [$time_local] $request '
#                  '"$status" $body_bytes_sent "$http_referer" '
#                  '"$http_user_agent" "$http_x_forwarded_for"';
#access_log  off;
access_log  logs/access.log;
client_header_timeout  3m;
client_body_timeout    3m;
send_timeout           3m;
client_header_buffer_size    1k;
large_client_header_buffers  4 4k;
sendfile        on;
tcp_nopush      on;
tcp_nodelay     on;
#keepalive_timeout  75 20;
include    gzip.conf;
upstream localhost {
#ip_hash
#ip_hash;
server localhost:18081;
server localhost:18080;
}
server {
listen       80;
server_name  localhost;
location / {
proxy_connect_timeout   3;
proxy_send_timeout      30;
proxy_read_timeout      30;
proxy_pass http://localhost;
}
}
}

  对于上面关于ubuntu下Nginx配置和window下基本相同,区别在用的IO|络模型Qlinux下徏议用epollQ另外就是运行所用的用户和组Q?/p>


3、配|tomcat

    请参考window下配|,完全相同?/p>

4、启动停止nginx

    ubuntu下启动nginx与windowE有不同Q大致启动停止方法如下?/p>


#nginx目录执行
sbin/nginx
或通过-c 指定配置文g
sbin/nginx -c usr/local/nginx8.20/conf/nginx/conf



niumd@niumd-laptop:/usr/local/nginx$ pwd
/usr/local/nginx
niumd@niumd-laptop:/usr/local/nginx$ sudo sbin/nginx -t
the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
configuration file /usr/local/nginx/conf/nginx.conf test is successful
niumd@niumd-laptop:/usr/local/nginx$ sudo sbin/nginx -v
nginx version: nginx/0.8.20
niumd@niumd-laptop:/usr/local/nginx$ sudo sbin/nginx -V
nginx version: nginx/0.8.20
built by gcc 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
configure arguments: --user=niumd --group=niumd --with-debug --with-http_sub_module
niumd@niumd-laptop:/usr/local/nginx$ sudo sbin/nginx
niumd@niumd-laptop:/usr/local/nginx$ ps -ef|grep nginx
root      5158     1  0 22:32 ?        00:00:00 nginx: master process sbin/nginx
niumd     5159  5158  0 22:32 ?        00:00:00 nginx: worker process
niumd     5161  1577  0 22:32 pts/0    00:00:00 grep --color=auto nginx
niumd@niumd-laptop:/usr/local/nginx$ 


     我们通过ps  -ef|grep nginx,看到如下l果:

   

注意Q在启动时linux提示一句警告【warn?#8230;…Q是因ؓ我们讄?#允许最大连接数 worker_connections  2048Q超qlinux默认1024的限制?/p>

       停止Qkill -信号cd pid

       nginx/logs目录下有个nginx。pid的文Ӟ此文件记录了每次q行的pidQ也可以通过ps命o查询?/p>

信号cd如下Q?/p>


信号控制
信号cd 描述
RERM.INT 快速关?/td>
HUP qx重启Q加载配|?/td>
USR1 重新加蝲日志
USER2 qx升执行E序
WINCH 从容关闭工作q程
QUIT 从容关闭


参考资料:

http://www.oschina.net/bbs/thread/9301

oschina.net 生配置Q此|站采用java语言QnginxQtomcat服务器?/p>

http://nginx.org/

张宴Q?lt;<实战Nginx>>




I白 2011-05-10 20:56 发表评论
]]>
Ubuntu11 Unity 2D桌面http://m.tkk7.com/niumd/archive/2011/05/10/349955.htmlI白I白Tue, 10 May 2011 12:54:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349955.htmlhttp://m.tkk7.com/niumd/comments/349955.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349955.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349955.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349955.html
Ubuntu11.04如何讄2D Unity桌面


    Ubuntu11.04一发布p不及待的鲜Q虚拟机环境不支持Unity 3D,试了下Unity 2DQ效果很炫。安装很单,l大家分享下?/p>

Terminal 键入如下命oQ?/span>


sudo add-apt-repository ppa:unity-2d-team/unity-2d-daily
sudo apt-get update
sudo apt-get install unity-2d
 

   q三行命令就不解释,Ubuntu新手老手都应该清楚,l过10-20分钟的等待(取决你的|速和选择更新源)QUbuntu安装Unity-2d和依赖包Q安装完毕,log outQ这Ҏwindows强,xp都是提示重启的?/p>


 上图Q登陆界面选择Unity 2D?/p>


 上图U桌面Q?/span>





I白 2011-05-10 20:54 发表评论
]]>
crontab命o用法http://m.tkk7.com/niumd/archive/2011/05/10/349957.htmlI白I白Tue, 10 May 2011 12:54:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349957.htmlhttp://m.tkk7.com/niumd/comments/349957.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349957.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349957.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349957.html

   Linux提供了用h制例行Q务的命ocrontabQ常用于每间隔一定时间@环执行一些脚本,此处我们暂时UCؓQLinux定时d?/p>


#问下男hcrontab的用?
man crontab
crontab [ -u user ] { -l | -r [ -i ] | -e }
参数Q?
-uQ只有root才可以执行此d
-l Q查看crontab工作内容
-eQ编辑crontab工作内容
-r Q删除crontab工作内容



   crontab应用场景举例Q定旉集远E服务器文g

   手机发送短信,短信回以文本形式记录在交换机上Ş成短信话单,短信话单通常是达?MQ如果不?m则每五分钟Ş成一个话单(不同的交换机可能存在差异Q。如果对话单计费Q当焉要对短信话单q行采集Q然后进行后l计费工作。我们假N用shell或者python脚本采集Q暂且用shell举例Q假N集shell为acquisition.sh Q每间隔1分钟采集一ơ?/p>


    命ol端执行Q?/p>


#标示~辑例行d
crontab -e

    然后我们会看到如下画面Q?/p>

 

 


   已经q入VI ~辑模式Q在里面输入下面q行Q按下ESC->Q?>wq׃存了

#每间隔一分钟执行一ơ采集脚?
*/1 * * * * crontab  /路径/acquisition.sh



    crontab的格式ؓQ?/p>

    分钟  时 ?nbsp; ??crontab   待执行命令或者脚?nbsp;


    其中Q? 代表M旉都接受,如上例小时、日期、月份、周都ؓ*

             Q代表分割时间段Q如分钟修改为:0,1,2,3,4,5 即Q何小时地1,2Q?#8230;…6分钟都执?/p>

             - 代表旉D上面的每间隔一分钟可以标示?-59Q?/p>

             /n 代表每间隔,分钟位置Q?/5标示每间隔五分钟


 注意Q??之间只有一个空|



EOF



I白 2011-05-10 20:54 发表评论
]]>
谈Selector创徏机制http://m.tkk7.com/niumd/archive/2011/05/10/349954.htmlI白I白Tue, 10 May 2011 12:53:00 GMThttp://m.tkk7.com/niumd/archive/2011/05/10/349954.htmlhttp://m.tkk7.com/niumd/comments/349954.htmlhttp://m.tkk7.com/niumd/archive/2011/05/10/349954.html#Feedback0http://m.tkk7.com/niumd/comments/commentRss/349954.htmlhttp://m.tkk7.com/niumd/services/trackbacks/349954.html

前段旉阅读mina源码Ӟ?/span>?span mce_style="font-family: monospace; white-space: pre;" style="font-family: monospace; white-space: pre; ">Selector实例化机制细节有点疑惑疑惑,主要?/span>SelectorProvider的细节实现方面?/span>

通常创徏一个SelectorQ通过静态openҎ创徏一个实例?/span>代码如下Q?/p>

Selector selector = Selector.open();


观察JDK源码发现Select的创建通过SelectorProvider辅助cL完成Q?/p>


public static Selector open() throws IOException {
return SelectorProvider.provider().openSelector();
}



q一步观?span mce_style="white-space: pre;" style="white-space: pre; ">SelectorProvidercproviderҎ源码Q引用到csun.nio.ch.DefaultSelectorProviderQ开始的时候由于在JDK API

中没扑ֈ该类Q源码里面也没找刎ͼ比较疑惑如何创徏的?/span>今天在rt.jar扑ֈ了该c,q找到其Ҏ码?/p>


/**
* Returns the default SelectorProvider.
*/
public static SelectorProvider create() {
PrivilegedAction pa = new GetPropertyAction("os.name");
String osname = (String) AccessController.doPrivileged(pa);
if ("SunOS".equals(osname)) {//1、如果SunOS
return new sun.nio.ch.DevPollSelectorProvider();
}
//2、Linux 内核>=2.6
// use EPollSelectorProvider for Linux kernels >= 2.6
if ("Linux".equals(osname)) {
pa = new GetPropertyAction("os.version");
String osversion = (String) AccessController
.doPrivileged(pa);
String[] vers = osversion.split("\\.", 0);
if (vers.length >= 2) {
try {
int major = Integer.parseInt(vers[0]);
int minor = Integer.parseInt(vers[1]);
if (major > 2 || (major == 2 && minor >= 6)) {
return new sun.nio.ch.EPollSelectorProvider();
}
} catch (NumberFormatException x) {
// format not recognized
}
}
}
return new sun.nio.ch.PollSelectorProvider();
}



?span mce_style="white-space: pre;" style="white-space: pre; ">createҎҎ不同的操作系l构Z同的SelectorProviderQ主要分为unix、linuxQotherQlinux针对内核2.6以上

通过epoll?/span>获取pȝ环境中的os.name、os.version观察下不同^台的l节?/span>


System.out.println(System.getProperty("os.name"));
System.out.println(System.getProperty("os.version"));
System.out.println(java.nio.channels.spi.SelectorProvider.provider());


 通过在不同的操作pȝ上执行如下代码即可区分:

win XP sp3Q?/p>


 写道
Windows XP
5.1
sun.nio.ch.WindowsSelectorProvider@1fb8ee3


 ubuntu 11.04Q?/p>


 写道
Linux
2.6.38-8-generic
sun.nio.ch.EPollSelectorProvider@160c21a


JDK对linux内核2.6以上版本默认采用epollQLinux下性能得到一定幅度提升?/p>



参考:

DefaultSelectorProvider源码Q?/span>http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Platform/solaris/sun/nio/ch/DefaultSelectorProvider.java.htm



I白 2011-05-10 20:53 发表评论
]]>
վ֩ģ壺 ޾ƷۺҰ| www.999ƷƵۿ| www.޾Ʒ.com| ԻƵ| һëƬ߹ۿ| ѲŮһëƬ| һػɫƬ | ۺһ| ѹ˦Ƭ| þ޾ƷĻ| ̼aƬվ| ޳aƬ߹| ëƬ߹ۿ| ޹ƷŮþþþ| 쿴ѸӰ| ŮƷĻ| Ƶ| ëƬ߿ò| þþþþ޾Ʒ| ޶߹ۿ | պ޴߶ȸ| ɫwwwվ| ޸һ| 鶹Ʒѹۿ| ֱƵ| AV˿߹ۿ| һëƬ| 99aƷ| ¾þþþa| ޳aƬ߹ۿձ| ˺Ů˸߳վ| ɫվ| ߹ۿվ| ۺվ| jizzjizzѿjizz| ߹ۿվ| ޹ֻߵӰbd| ղƷϵ| 69ƷƵ| AVһ| av뾫Ʒ|