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]

你可能感兴趣的:(DAO,apache,bean,struts,ibatis)