`
石建武
  • 浏览: 74939 次
  • 性别: Icon_minigender_1
  • 来自: 陕西
社区版块
存档分类
最新评论

JPetStore简单分析

阅读更多

自己简单的分析了下JPetStore的结构,但一些问题依然没有解决,先写出来自己知道的,希望可以给别人帮助,也希望高手给指点下 。。。

一. JPetStore特有的结合struts的前端控制

1. web.xml 配置信息,是常规的配置[size=xx-small]

   依然是简单的所有以 *.shtml 结尾的请求统一由ActionServlet处理
<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
      <param-name>debug</param-name>
      <param-value>2</param-value>
    </init-param>
    <init-param>
      <param-name>detail</param-name>
      <param-value>2</param-value>
    </init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>action</servlet-name>
   <url-pattern>*.shtml</url-pattern>
</servlet-mapping>

2. struts.xml 配置信息
<action path="/shop/index"       type="org.apache.struts.beanaction.BeanAction"
    name="catalogBean"
         parameter="*"
             validate="false">
      <forward name="success" path="/catalog/Main.jsp"/>
</action>
所有的请求经ActionServlet之后都交给了BeanAction处理。可以很好的看看作者的对BeanAction的注释,作者的意图很清楚:降低对struts的依赖。
注释:BeanAction is an extension to the typical Struts Action class that enables mappings to bean methods. In addition to the simpler packaging, BeanAction also simplifies the Struts progamming paradigm and reduces dependency on Struts.  Using this pattern could allow easier migration to newer frameworks like JSF.

3. 所有的 Bean 继承了BaseBane ,BaseBean继承了ActionForm 。JPetStore中对业务的实际操作交给了实体Bean自己实现。包 presentation 中所有的 Bean 内部都定义了自己的处理业务逻辑的方法。目的 :业务的处理,不再是继承Struts的Action ,然后调用execute方法,这样大大的降低了“struts的侵入性”。

4. 处理流程:struts 的基本处理后调用 BeanAction 的 execute ()方法
public class BeanAction extends Action {

  private static final String NO_METHOD_CALL = "*";
  private static final String SUCCESS_FORWARD = "success";

  // 普通的的Action的execute方法
  public final ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
String forward = SUCCESS_FORWARD;

(1)
// BeanAction要求必须要有form的配置,因为业务的处理是直接交给bean实体
// 若没有form的配置,则直接报错
try {
      if (!(form instanceof BaseBean)) {
        if (form != null) {
          throw new BeanActionException("The form for mapping '" + mapping.getPath() + "' named '" + mapping.getName() + "' was not an instance of BaseBean.  BeanAction requires an BaseBean instance.");
        } else {
          throw new BeanActionException("The form for mapping '" + mapping.getPath() + "' named '" + mapping.getName() + "' was null.  BeanAction requires an BaseBean instance.");
        }
      }



(2)
  // 因为所有的bean的都继承了BaseBean,当然BaseBean也是继承ActionForm 。
      BaseBean bean = (BaseBean) form;
      ActionContext.initCurrentContext(request, response);

      if (bean != null) {

        // Explicit Method Mapping
        Method method = null;
   // (2.1)
   // 获取Action parameter="*" 的参数,作为methodName
        String methodName = mapping.getParameter();
  
   (2.1.1)
// 根据 methodName 调用Bean实体的方法
         // method = bean.getClass().getMethod(methodName, null); 利用反射实现
        if (methodName != null && !NO_METHOD_CALL.equals(methodName)) {
          try {
            method = bean.getClass().getMethod(methodName, null);
  //问题 : 对bean实体的同步 ,会不会影响性能,对于同一个bean的多个请求的并发?
            synchronized (bean) {
// return (String) method.invoke(bean, null);此方法具体返回的是“实际调用    的方法的返回值”。如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0       或 null,即调用的方法不需要参数。
              forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
            }
          } catch (Exception e) {
            throw new BeanActionException("Error dispatching bean action via method parameter ('" + methodName + "').  Cause: " + e, e);
          }
        }

(2.2.2)
// 当没有定义parameter参数的时候,根据url截取methodName的值,然后的调用和上面相 // 同。
        // Path Based Method Mapping
        if (method == null && !NO_METHOD_CALL.equals(methodName)) {
          methodName = mapping.getPath();
          if (methodName.length() > 1) {
            int slash = methodName.lastIndexOf("/") + 1;
            methodName = methodName.substring(slash);
            if (methodName.length() > 0) {
              try {
                method = bean.getClass().getMethod(methodName, null);
                synchronized (bean) {
                  forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
                }
              } catch (Exception e) {
                throw new BeanActionException("Error dispatching bean action via URL pattern ('" + methodName + "').  Cause: " + e, e);
              }
            }
          }
        }
      }
    } catch (Exception e) {
      forward = "error";
      request.setAttribute("BeanActionException", e);
}

(2.2.3)
// 1. 若parameter参数为 “*” ,即不调用Bean的任何方法,forward=success
// 2. 正确的执行得到了 forward 值,则根据forward 跳转
// 3. 此forward参数的值对应于Action的子标签forward的name属性值
    return mapping.findForward(forward);
  }
}

附:作者对方法调用的说明
 
* There are 3 ways to map a BeanAction in the struts configuration file.
 * <p/>
 * They are as follows.
 * <p/>
 * <p/>
 * <p/>
 * <B>URL Pattern</B>
 * <p/>
 * <p/>
 * <p/>
 * This approach uses the end of the action definition to determine which
 * <p/>
 * method to call on the Bean.  For example if you request the URL:
 * <p/>
 * <p/>
 * <p/>
 * http://localhost/jpetstore4/shop/viewOrder.do
 * <p/>
 * <p/>
 * <p/>
 * Then the method called would be "viewOrder" (of the mapped bean as 	specified
 * <p/>
 * by the name="" parameter in the mapping below).  The mapping used for 	this
 * <p/>
 * approach is as follows.
 * <p/>
 * <pre>
 * <p/>
 *  &lt;action path="/shop/<b>viewOrder</b>" 	type="org.apache.struts.beanaction.BeanAction"
 * <p/>
 *    name="orderBean" scope="session"
 * <p/>
 *    validate="false"&gt;
 * <p/>
 *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
 * <p/>
 *  &lt;/action&gt;
 * <p/>
 * </pre>
 * <p/>
 * <p/>
 * <p/>
 * <B>Method Parameter</B>
 * <p/>
 * <p/>
 * <p/>
 * This approach uses the Struts action parameter within the mapping
 * <p/>
 * to determine the method to call on the Bean.  For example the
 * <p/>
 * following action mapping would cause the "viewOrder" method to
 * <p/>
 * be called on the bean ("orderBean").  The mapping used for this
 * <p/>
 * approach is as follows.
 * <p/>
 * <pre>
 * <p/>
 *  &lt;action path="/shop/viewOrder" 	type="org.apache.struts.beanaction.BeanAction"
 * <p/>
 *    <b>name="orderBean" parameter="viewOrder"</b> scope="session"
 * <p/>
 *    validate="false"&gt;
 * <p/>
 *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
 * <p/>
 *  &lt;/action&gt;
 * <p/>
 * </pre>
 * <p/>
 * <B>No Method call</B>
 * <p/>
 * <p/>
 * <p/>
 * BeanAction will ignore any Struts action mappings without beans 	associated
 * <p/>
 * to them (i.e. no name="" attribute in the mapping).  If you do want 	to associate
 * <p/>
 * a bean to the action mapping, but do not want a method to be called, 	simply
 * <p/>
 * set the parameter to an asterisk ("*").  The mapping used for this 	approach
 * <p/>
 * is as follows (no method will be called).
 * <p/>
 * <pre>
 * <p/>
 *  &lt;action path="/shop/viewOrder" 	type="org.apache.struts.beanaction.BeanAction"
 * <p/>
 *    <b>name="orderBean" parameter="*"</b> scope="session"
 * <p/>
 *    validate="false"&gt;
 * <p/>
 *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
 * <p/>
 *  &lt;/action&gt;
 * <p/>
 * </pre>


5. synchronized (bean) {
     forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
   }
BaseBean的内部持有 ActionInterceptor ,内部定义了这样的方法  String intercept(ActionInvoker invoker); 作为参数的ActionInvoke,内部持有对应的Bean和Method,然后调用 method.invoke(bean, null);完成操作。



二. DAO设计
例子:查询某产品
---- 一个请求到达BeanAction处理
---- 调用 CatalogBean 的 public String searchProducts() 
---- 调用 catalogService.searchProductList()
public PaginatedList searchProductList(String keywords) {
  return productDao.searchProductList(keywords);
}
---- public CatalogService() {
DaoManager daoManager = DaoConfig.getDaoManager();
productDao = (ProductDao) daoManager.getDao(ProductDao.class);
}

--------- DaoConfig (主要代码)
public class DaoConfig {
  private static final String resource =    "com/ibatis/jpetstore/persistence/dao.xml";
  private static final DaoManager daoManager;

static {
     daoManager = newDaoManager(null);
}
public static DaoManager newDaoManager(Properties props) {
    try {
      Reader reader = Resources.getResourceAsReader(resource);
      return DaoManagerBuilder.buildDaoManager(reader, props);
    }
  }

补充:"com/ibatis/jpetstore/persistence/dao.xml";
<daoConfig>
  <context>
// 指定了全局的配置文件的url
    <transactionManager type="SQLMAP">
      <property name="SqlMapConfigResource"
        value="com/ibatis/jpetstore/persistence/sqlmapdao/sql/sql-map-config.xml"/>
</transactionManager>
//指定dao的接口和实现
    <dao interface="com.ibatis.jpetstore.persistence.iface.ItemDao"
    implementation="com.ibatis.jpetstore.persistence.sqlmapdao.ItemSqlMapDao"/>
  </context>
</daoConfig>
----- DaoManagerBuilder 读取配置文件,并返回DaoManager的一个实例
---- DaoManager
/**
   * Gets a Dao instance for the requested interface type
   * @param type The interface or generic type for which an implementation
   *         should be returned.
   * @return The Dao implementation instance.
   */
  public Dao getDao(Class type);
  例:categoryDao = (CategoryDao) daoManager.getDao(CategoryDao.class); CategoryDao即为一个借口,具体的实现为CategorySqlMapDao 。根据dao.xml配置,通过反射实例化CategorySqlMapDao。

---- 方法调用返回 。。。。

补充:资源文件读取的保存

读取后的资源的文件的内容是存放DaoManager里面。资源文件的读取必须是只能读取一次,目的:效率。自己以后实现简单dao的时候,借鉴。

public class StandardDaoManager implements DaoManager {
  private ThreadLocal transactionMode = new ThreadLocal();
  private ThreadLocal contextInTransactionList = new ThreadLocal();

  private Map idContextMap = new HashMap();
  private Map typeContextMap = new HashMap();
  private Map daoImplMap = new HashMap();
}

使用ibatis-dao,继承com.ibatis.dao.client.template.SqlMapDaoTemplate类。


三.问题:

DaoManager获取Dao的时候,先取得DaoContext,再通过DaoContext取得DaoImp,调用的impl.getProxy()方法返回一个Dao :
public Dao getProxy() {
   return proxy;
  }
在DaoProxy有这样的方法:
public void initProxy() {
    proxy = DaoProxy.newInstance(this);
}
DaoProxy的方法newInstance():采用动态代理
public static Dao newInstance(DaoImpl daoImpl) {
    return (Dao) Proxy.newProxyInstance(daoImpl.getDaoInterface().getClassLoader(),
        new Class[]{Dao.class, daoImpl.getDaoInterface()},
        new DaoProxy(daoImpl));
  }

在这自己的思路有些混乱,没有搞清楚作者的思路到底是怎样的?希望高手可以指点下!


附:ibatis-dao图 (不知道咋上传图呢,大家可以去看看ibtais-dao的自己的图。结构描述真的很清晰!)[/size]
0
0
分享到:
评论

相关推荐

    JPetStore4.0.5

    JPetStore4.0.5是一个基于Java的开源电子商务应用,它展示了如何有效地利用Ibatis和Struts框架构建一个简单而实用的在线商店系统。这个版本在设计上保持了简洁性,非常适合小型项目的需求,为开发者提供了快速搭建...

    iBATIS_JPetStore-4.0.5

    它通过XML配置文件定义了SQL语句和Java对象之间的映射关系,使得数据库操作变得简单而直观。而Spring框架可能被用来管理事务、依赖注入和控制流程,提供更高级别的服务。 此外,JPetStore是一个经典的电子商务示例...

    jpetstore.zip

    本文将深入探讨如何将原版的jpetstore项目改造成SSM架构,并分析其中的技术要点。 首先,我们来看SSM框架的核心构成: 1. **Spring**:作为全能型的IOC(Inversion of Control)/AOP(Aspect Oriented Programming...

    springMVC自带的jpetstore源码

    **Spring MVC 自带的 JPetStore 源码解析** `Spring MVC` 是一个轻量级的、模型-视图-控制器(Model-...通过学习和分析 `jpetstore`,开发者可以更好地理解和掌握 Spring MVC 的工作原理,为自己的项目开发提供借鉴。

    Spring jpetstore

    Spring JDBC通过DataSource、JdbcTemplate或NamedParameterJdbcTemplate等类,使得编写SQL语句和处理结果集变得更加简单和直观。 ### 3. 源码分析 jpetstore的源代码是学习Spring框架的一个绝佳资源。通过阅读源码...

    springmvc深入解析.pdf

    业务层其实很简单,主要是一个PetStoreFacade接口,该接口在JPetStore中只有一个唯一的实现类PetStoreImpl,它提供了很多供Web层调用的方法,而绝大多数方法都只是简单的调用了数据访问层的Dao类所提供的方法。...

    Tutorial

    通过分析JPetStore的实现,我们可以更好地理解如何有效地将iBATIS与Derby结合起来使用。 - **数据模型**:JPetStore使用了一组精心设计的实体类来表示其业务对象,这些实体类与Derby数据库中的表相对应。每个实体类...

    .Net PetStore 和 Java PetShop 架构对比分析

    本文将通过分析Microsoft .NET Pet Shop 4与JPetStore 5.0这两个示例项目,探讨它们的架构特点和技术优势,为程序员提供参考。 首先,我们关注.NET Pet Shop 4,这是一个基于ASP.NET 2.0的示例应用,展示了新版本的...

    ibatis3.0示例

    iBatis 3.0引入了Executor执行器,包括SimpleExecutor、ReuseExecutor和BatchExecutor,分别对应简单执行、重用Statement和批量操作,提供了不同的性能优化策略。 6. **缓存机制** iBatis支持本地缓存和二级缓存...

    对于Spring初学者的学习建议.pdf

    通过研究Spring开源项目,比如Spring自带的jpetstore,可以加深对Spring框架使用方法的理解。分析别人的项目代码,看看在实际开发中如何应用Spring框架,能帮助初学者更好地理解如何将理论知识应用到实践中。 四、...

    国外的ibatis写的宠物网站

    Ibatis是一款轻量级的Java持久层框架,它主要处理应用程序与数据库之间的交互,提供了一种简单但灵活的方式来映射SQL语句到Java对象。这个网站可能是用Java语言编写,前端可能使用JSP(Java Server Pages)技术来...

    Ibatis开发实例

    它通过提供一种简单的方式来处理 SQL 查询和结果集映射,从而简化了 Java 应用程序与数据库之间的交互。 #### 二、Spring宠物店项目中的Ibatis应用 Spring宠物店是一个非常典型的展示了 Spring 和 Ibatis 整合的...

    对于Spring初学者的学习建议

    - **Factory模式**(包括简单工厂和抽象工厂):帮助理解Spring中的Bean创建方式。 - **Strategy模式**:了解如何在Spring中使用不同的策略实现特定功能。 - **Template Method模式**:理解Spring中的模板方法...

    mybatis-spring整合项目

    MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 二、Spring框架介绍 Spring是一个开源的应用框架,也是依赖注入(DI)容器...

    云计算应用开发实践

    本章介绍了如何将一个简单的应用移植到云计算环境中,并通过Java宠物商店案例逐步展示了云计算应用程序、云计算环境以及云计算概念的产生与发展。通过实践学习,开发者可以更好地理解云计算的基本概念和技术特点,为...

    J2EE入门-经典

    - **阅读经典代码**:通过分析优秀项目如Petstore、JPetstore、Jive、Appfuse等,学习先进的设计思路。 - **实践为主**:理论与实践相结合,动手编写代码比单纯阅读书籍更有助于技能提升。 - **广泛涉猎**:保持对新...

Global site tag (gtag.js) - Google Analytics