Struts2源码阅读之UtilTimerStatck和ProfilingTimerBean类学习

UtilTimerStatck类:用于记录代码执行的时间工具类

ProfilingTimerBean类:javabean类,包含一些startTime,totalTime,resource,parent,children等属性

用于时间的记录以及堆栈的实现。

使用步骤:

1.struts2配置文件配置:<constant name="struts.devMode" value="true"/>

2.在指定的action中进行配置:

  <interceptor-ref name="profiling">
    	<param name="profilingKey">profiling</param>
  </interceptor-ref>

3.访问时例如:http://localhost:8000/StrutsStudy/action001.do?profiling=true

结果:

[2000ms] - EncodingFilter_doFilter:
   [2000ms] - FilterDispatcher_doFilter: 
     [2000ms] - Handling request from Dispatcher
       [0ms] - create DefaultActionProxy: 
         [0ms] - create DefaultActionInvocation: 
           [0ms] - actionCreate: action001
       [2000ms] - invoke: 
         [2000ms] - interceptor: profiling
           [2000ms] - invoke: 
             [2000ms] - invokeAction: action001
             [0ms] - executeResult: success

源码如下:

UtilTimerStack类:

public class UtilTimerStack
 {
 
     // A reference to the current ProfilingTimerBean
     protected static ThreadLocal<ProfilingTimerBean> current = new ThreadLocal<ProfilingTimerBean>();
 
     /**
      * System property that controls whether this timer should be used or not.  Set to "true" activates
      * the timer.  Set to "false" to disactivate.
      */
     public static final String ACTIVATE_PROPERTY = "xwork.profile.activate";
 
     /**
      * System property that controls the min time, that if exceeded will cause a log (at INFO level) to be
      * created.
      */
     public static final String MIN_TIME = "xwork.profile.mintime";
     
     private static final Log log = LogFactory.getLog(UtilTimerStack.class);
 
     /**
      * Create and start a performance profiling with the <code>name</code> given. Deal with 
      * profile hierarchy automatically, so caller don't have to be concern about it.
      * 
      * 
      * 
      * 
      * 
      * @param name profile name
      */
     public static void push(String name)
     {	//判断该诊断工具是否激活
         if (!isActive())
             return;
 
         //create a new timer and start it
         //本地线程变量-相关时间配置bean
         ProfilingTimerBean newTimer = new ProfilingTimerBean(name);
         newTimer.setStartTime();
 
         //if there is a current timer - add the new timer as a child of it
         //如果当前线程未绑定,那么进行绑定,否则直接获取
         ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get();
         if (currentTimer != null)
         {
         	//当且仅当继续使用本地线程并同时调用push操作时,即添加其儿子节点,并同时添加当前儿子节点的父节点
         	/**
         	 *很给力的设计:更改currentTimer(bean)的内容(添加子节点),同时将该父亲bean添加到newTimer中去
         	 *				因此我觉得bean的设计不是树的结构,而是堆栈的思路
         	 * public void addChild(ProfilingTimerBean child){
 			        children.add(child);
 			        child.addParent(this);
 			   }
         	 */
             currentTimer.addChild(newTimer);
         }
 
         //set the new timer to be the current timer
         //设置新的线程变量
         current.set(newTimer);
     }
 
     /**
      * End a preformance profiling with the <code>name</code> given. Deal with
      * profile hierarchy automatically, so caller don't have to be concern about it.
      * 
      * @param name profile name
      */
     public static void pop(String name)
     {
         if (!isActive())
             return;
         //获取本地线程变量bean
         ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get();
 
         //if the timers are matched up with each other (ie push("a"); pop("a"));
         if (currentTimer != null && name != null && name.equals(currentTimer.getResource()))
         {
         	//设置本地线程变量bean的终结时间
             currentTimer.setEndTime();
             ProfilingTimerBean parent = currentTimer.getParent();
             //if we are the root timer, then print out the times
             if (parent == null)
             {
             	//且只有当线程变量的父节点为null时,才会答应
                 printTimes(currentTimer);
                 current.set(null); //for those servers that use thread pooling
             }
             else
             {
                 current.set(parent);
             }
         }
         else
         {
             //if timers are not matched up, then print what we have, and then print warning.
             if (currentTimer != null)
             {
                 printTimes(currentTimer);
                 current.set(null); //prevent printing multiple times
                 log.warn("Unmatched Timer.  Was expecting " + currentTimer.getResource() + ", instead got " + name);
             }
         }
 
 
     }
 
     /**
      * Do a log (at INFO level) of the time taken for this particular profiling.
      * 
      * @param currentTimer profiling timer bean
      */
     private static void printTimes(ProfilingTimerBean currentTimer)
     {
         log.info(currentTimer.getPrintable(getMinTime()));
     }
 
     /**
      * Get the min time for this profiling, it searches for a System property
      * 'xwork.profile.mintime' and default to 0.
      * 
      * @return long
      */
     private static long getMinTime()
     {
         try
         {
             return Long.parseLong(System.getProperty(MIN_TIME, "0"));
         }
         catch (NumberFormatException e)
         {
            return -1;
         }
     }
 
     /**
      * Determine if profiling is being activated, by searching for a system property
      * 'xwork.profile.activate', default to false (profiling is off).
      * 
      * @return <tt>true</tt>, if active, <tt>false</tt> otherwise.
      */
     public static boolean isActive()
     {
         return System.getProperty(ACTIVATE_PROPERTY) != null;
     }
 
     /**
      * Turn profiling on or off.
      * 诊断工具开启与否的设计,通过System.setProperty
      * @param active
      */
     public static void setActive(boolean active)
     {
         if (active)
             System.setProperty(ACTIVATE_PROPERTY, "true");
         else
         	System.clearProperty(ACTIVATE_PROPERTY);
     }
 
 
     /**
      * A convenience method that allows <code>block</code> of code subjected to profiling to be executed 
      * and avoid the need of coding boiler code that does pushing (UtilTimeBean.push(...)) and 
      * poping (UtilTimerBean.pop(...)) in a try ... finally ... block.
      * 
      * <p/>
      * 
      * Example of usage:
      * <pre>
      * 	 // we need a returning result
      *   String result = UtilTimerStack.profile("purchaseItem: ", 
      *       new UtilTimerStack.ProfilingBlock<String>() {
      *            public String doProfiling() {
      *               getMyService().purchaseItem(....)
      *               return "Ok";
      *            }
      *       });
      * </pre>
      * or
      * <pre>
      *   // we don't need a returning result
      *   UtilTimerStack.profile("purchaseItem: ", 
      *       new UtilTimerStack.ProfilingBlock<String>() {
      *            public String doProfiling() {
      *               getMyService().purchaseItem(....)
      *               return null;
      *            }
      *       });
      * </pre>
      * 
      * @param <T> any return value if there's one.
      * @param name profile name
      * @param block code block subjected to profiling
      * @return T
      * @throws Exception
      */
     public static <T> T profile(String name, ProfilingBlock<T> block) throws Exception {
     	UtilTimerStack.push(name);
     	try {
     		return block.doProfiling();
     	}
     	finally {
     		UtilTimerStack.pop(name);
     	}
     }
     
     /**
      * A callback interface where code subjected to profile is to be executed. This eliminates the need
      * of coding boiler code that does pushing (UtilTimerBean.push(...)) and poping (UtilTimerBean.pop(...))
      * in a try ... finally ... block.
      * 
      * @version $Date$ $Id$
      * 
      * @param <T>
      */
     public static interface ProfilingBlock<T> {
     	
     	/**
     	 * Method that execute the code subjected to profiling.
     	 * 
     	 * @return  profiles Type
     	 * @throws Exception
     	 */
     	T doProfiling() throws Exception;
     }
 }


ProfilingTimerBean类:这个类比较容易看懂,因此未加任何注释。

public class ProfilingTimerBean implements java.io.Serializable {
 	
 	private static final long serialVersionUID = -6180672043920208784L;
 	
 	List<ProfilingTimerBean> children = new ArrayList<ProfilingTimerBean>();
     ProfilingTimerBean parent = null;
 
     String resource;
 
     long startTime;
     long totalTime;
 
     public ProfilingTimerBean(String resource)
     {
         this.resource = resource;
     }
 
     protected void addParent(ProfilingTimerBean parent)
     {
         this.parent = parent;
     }
 
     public ProfilingTimerBean getParent()
     {
         return parent;
     }
 
 
     public void addChild(ProfilingTimerBean child)
     {
         children.add(child);
         child.addParent(this);
     }
 
 
     public void setStartTime()
     {
         this.startTime = System.currentTimeMillis();
     }
 
     public void setEndTime()
     {
         this.totalTime = System.currentTimeMillis() - startTime;
     }
 
     public String getResource()
     {
         return resource;
     }
 
     /**
      * Get a formatted string representing all the methods that took longer than a specified time.
      */
 
     public String getPrintable(long minTime)
     {
         return getPrintable("", minTime);
     }
 
     protected String getPrintable(String indent, long minTime)
     {
         //only print the value if we are larger or equal to the min time.
         if (totalTime >= minTime)
         {
             StringBuffer buffer = new StringBuffer();
             buffer.append(indent);
             buffer.append("[" + totalTime + "ms] - " + resource);
             buffer.append("\n");
 
             Iterator childrenIt = children.iterator();
             while (childrenIt.hasNext())
             {
                 buffer.append(((ProfilingTimerBean) childrenIt.next()).getPrintable(indent + "  ", minTime));
             }
 
             return buffer.toString();
         }
         else
             return "";
     }
 }


总结:需慢慢回味:

1.栈的设计思路

2.ThreadLocal的理解使用(同步访问解决的新思路)

3.设置启动与否的新思路(System.property)

4.log4g的简单使用



你可能感兴趣的:(struts2)