??xml version="1.0" encoding="utf-8" standalone="yes"?>在线日韩一区,青草在线视频在线观看,在线不卡一区二区http://www.aygfsteel.com/niumd/category/32382.html天行健、君子以自强不息 Q地势坤、君子以厚d载物…?/description>zh-cnWed, 11 May 2011 02:52:47 GMTWed, 11 May 2011 02:52:47 GMT60Spring JDBC Framework详解——批量JDBC操作、ORM映射http://www.aygfsteel.com/niumd/archive/2011/05/10/349965.htmlI白I白Tue, 10 May 2011 13:06:00 GMThttp://www.aygfsteel.com/niumd/archive/2011/05/10/349965.htmlhttp://www.aygfsteel.com/niumd/comments/349965.htmlhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349965.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/349965.htmlhttp://www.aygfsteel.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://www.aygfsteel.com/niumd/archive/2011/05/10/349964.htmlI白I白Tue, 10 May 2011 13:04:00 GMThttp://www.aygfsteel.com/niumd/archive/2011/05/10/349964.htmlhttp://www.aygfsteel.com/niumd/comments/349964.htmlhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349964.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/349964.htmlhttp://www.aygfsteel.com/niumd/services/trackbacks/349964.html阅读全文

I白 2011-05-10 21:04 发表评论
]]>
目重构之命令模?/title><link>http://www.aygfsteel.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://www.aygfsteel.com/niumd/archive/2011/05/10/349962.html</guid><wfw:comment>http://www.aygfsteel.com/niumd/comments/349962.html</wfw:comment><comments>http://www.aygfsteel.com/niumd/archive/2011/05/10/349962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/niumd/comments/commentRss/349962.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.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://www.aygfsteel.com/niumd/aggbug/349962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/niumd/" target="_blank">I白</a> 2011-05-10 21:03 <a href="http://www.aygfsteel.com/niumd/archive/2011/05/10/349962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入出ThreadLocalhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349961.htmlI白I白Tue, 10 May 2011 13:02:00 GMThttp://www.aygfsteel.com/niumd/archive/2011/05/10/349961.htmlhttp://www.aygfsteel.com/niumd/comments/349961.htmlhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349961.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/349961.htmlhttp://www.aygfsteel.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://www.aygfsteel.com/niumd/archive/2011/05/10/349960.htmlI白I白Tue, 10 May 2011 13:01:00 GMThttp://www.aygfsteel.com/niumd/archive/2011/05/10/349960.htmlhttp://www.aygfsteel.com/niumd/comments/349960.htmlhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349960.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/349960.htmlhttp://www.aygfsteel.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://www.aygfsteel.com/niumd/archive/2011/05/10/349959.htmlI白I白Tue, 10 May 2011 12:58:00 GMThttp://www.aygfsteel.com/niumd/archive/2011/05/10/349959.htmlhttp://www.aygfsteel.com/niumd/comments/349959.htmlhttp://www.aygfsteel.com/niumd/archive/2011/05/10/349959.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/349959.htmlhttp://www.aygfsteel.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 发表评论
]]>
NetBean6字体配置http://www.aygfsteel.com/niumd/archive/2008/09/07/227537.htmlI白I白Sun, 07 Sep 2008 05:46:00 GMThttp://www.aygfsteel.com/niumd/archive/2008/09/07/227537.htmlhttp://www.aygfsteel.com/niumd/comments/227537.htmlhttp://www.aygfsteel.com/niumd/archive/2008/09/07/227537.html#Feedback2http://www.aygfsteel.com/niumd/comments/commentRss/227537.htmlhttp://www.aygfsteel.com/niumd/services/trackbacks/227537.html阅读全文

I白 2008-09-07 13:46 发表评论
]]>
Spring之BeanFactory与ApplicationConText区别http://www.aygfsteel.com/niumd/archive/2008/06/22/209873.htmlI白I白Sun, 22 Jun 2008 10:34:00 GMThttp://www.aygfsteel.com/niumd/archive/2008/06/22/209873.htmlhttp://www.aygfsteel.com/niumd/comments/209873.htmlhttp://www.aygfsteel.com/niumd/archive/2008/06/22/209873.html#Feedback0http://www.aygfsteel.com/niumd/comments/commentRss/209873.htmlhttp://www.aygfsteel.com/niumd/services/trackbacks/209873.htmlimport org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class XmlConfigWithBeanFactory {

    
public static void main(String[] args) {
        XmlBeanFactory factory 
= new XmlBeanFactory(new FileSystemResource(
                
"build/beans.xml"));

    }

}

    使用ApplicationConText从xml配置文g加蝲bean:
public class XmlConfigWithApplication{

    
public static void main(String[] args){
        ApplicationContext application 
= new ClassPathXmlApplicationContext(beans.xml"));
         application.getBean("BeanName");
    }

}

    ApplicationContext和BeanFacotry相比,提供了更多的扩展功能Q但其主要区别在于后者是延迟加蝲,如果Bean的某一个属性没有注入,BeanFacotry加蝲后,直至W一ơ用调用getBeanҎ才会抛出异常Q而ApplicationContext则在初始化自w是验,q样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext.

I白 2008-06-22 18:34 发表评论
]]>
使用Xfire开发WebServicehttp://www.aygfsteel.com/niumd/archive/2008/06/20/209404.htmlI白I白Fri, 20 Jun 2008 04:10:00 GMThttp://www.aygfsteel.com/niumd/archive/2008/06/20/209404.htmlhttp://www.aygfsteel.com/niumd/comments/209404.htmlhttp://www.aygfsteel.com/niumd/archive/2008/06/20/209404.html#Feedback2http://www.aygfsteel.com/niumd/comments/commentRss/209404.htmlhttp://www.aygfsteel.com/niumd/services/trackbacks/209404.html 下面是我们设计的webservice的接?
 1package com.test.service;
 2
 3import java.util.List;
 4
 5public interface IPerson {
 6    //Ҏ用户名获取密?/span>
 7    public String getPassword(String name);
 8    //Ҏ用户名获取Person对象
 9    public Person getPersonByName();
10    //获取全部成员
11    public List<Person> getAllPerson();
12}

其中有三个方法包含了传?String,Object,List集合;
2,q里我们实现接口中定义的业务逻辑
package com.test.service;

import java.util.LinkedList;
import java.util.List;

public class PersonImpl implements IPerson {
    
    
    
public String getPassword(String name) {
        
        
return "Password";
    }


    
public Person getPersonByName() {
        
        
return new Person("ObjectName","ObjectPass");
    }


    
public java.util.List<Person> getAllPerson(){
        
        List list 
= new LinkedList();
        list.add(
new Person("One","PassOne"));
        list.add(
new Person("Two","PassTwo"));
        list.add(
new Person("Three","PassThree"));
        
return list;
    }

}

在实际应用中比较复杂,可能用调用持久层的Dao,q回需要的l果,q里我们直接创徏一个模拟数?下面是实现类中用到的对象
 1package com.test.service;
 2
 3public class Person {
 4    private String name;
 5    private String password;
 6    
 7    public Person() {
 8        super();
 9    }

10    public Person(String name, String password){
11        super();
12        this.name = name;
13        this.password = password;
14    }

15    public String getPassword(){
16        return password;
17    }

18    public void setPassword(String password){
19        this.password = password;
20    }

21}

22

3,~写XFire要求的WebSevice定义描述文gQ如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xfire.codehaus.org/config/1.0">

    
<service>
        
<name>Person</name>
        
<serviceClass>com.test.service.IPerson</serviceClass>
        
<implementationClass>
            com.test.service.PersonImpl
        
</implementationClass>
        
<style>wrapped</style>
        
<use>literal</use>
        
<scope>application</scope>
    
</service></beans>
本文件的攄位置很关?此文件放在src/META-INF/xfire/services.xmlQ如果用MyEclipse新徏的不是webapplication,而是webservice目,q一步就省去自己~写?~译时会自动~译到classes的相应目录下面。web.z
5,~译xml,定义XfireConfigableServlet
 1<?xml version="1.0" encoding="UTF-8"?>
 2<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 3  <servlet>
 4    <servlet-name>XFireServlet</servlet-name>
 5    <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
 6    <load-on-startup>0</load-on-startup>
 7  </servlet>
 8  <servlet-mapping>
 9    <servlet-name>XFireServlet</servlet-name>
10    <url-pattern>/services/*</url-pattern>
11  </servlet-mapping>
12  <welcome-file-list>
13    <welcome-file>index.jsp</welcome-file>
14  </welcome-file-list>
15</web-app>
16
17
所有的工作都已l作完,接下来在部v在tomcate下,启动服务器,在地址栏键入:http://127.0.0.1:8080/MyWebService/srevice/Person?wsdl
如果出现xml描述文g成功了Q?br />



I白 2008-06-20 12:10 发表评论
]]>
վ֩ģ壺 ľ| | ƽ| | ¹Ȫ| | ľ˹| | | ۳| ̺| ޻| Ž| | | | ʯɽ| ƽ| ͺ| | | ҽ| Ԫ| | ¹| | ٲ| կ| | ˮ| | | ڽ| ½| | ˳| ʯ| | ָɽ| | ˮ|