Struts2源码学习笔记(一)

Struts2的入口类是StrutsPrepareAndExecuteFilter.java。这个类继承Filter接口,必须实现init()、doFilter()、destroy()这3个方法。其中,最重要的是doFilter()方法

 public abstract void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
        throws IOException, ServletException;
这里我经常搞混Filter接口的doFileter()方法入参中的ServletRequest、ServletResponse和HttpServlet抽象类的doPost()和doGet()方法的入参HttpServletRequest、HttpServletResponse。其实HttpServletRequest和HttpServletResponse分别是ServletRequest和ServletResponse的子接口,只不过增加了对Http协议的支持。
实际上,可以看到很多doFilter()方法里面的代码将ServletRequest和ServletResponse强制转换成HttpServletRequest和HttpServletResponse以便使用子接口中的方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
    ...
        chain.doFilter(request, response);
        ...
}


现在看下StrutsPrepareAndExecuteFilter这个类中的主要的成员变量PrepareOperations和ExecuteOperations和方法init()、doFilter()、destroy()。
就代码看PrepareOperations这个类主要是为运行的环境做准备工作,比如创建Action运行的上下文,初始化一个重要的类Dispatcher以及从配置中取得struts的action映射;而ExecuteOperations这个类主要是加载静态资源和用之前PrepareOpertions中已经初始化完成的Dispatcher去执行Action


首先是日志的处理。对于日志的处理有很多实现,包括很多第三方的SLF4J,Apache自己的Common-logging,其实JDK本身也有日志的实现。
Struts2的日志是这样处理的:首先set指定的日志工厂,然后需要的时候再取得。取的时候,
第1步.先根据运行参数设置的xwork.loggerFactory
然后使用反射获得日志工厂
第2步.如果第1步获取不到日志工厂,则使用apache的commons-logging的日志工厂
第3步.如果第2步获取不到日志工厂,则使用slf4j的日志工厂
第4步.如果第3步获取不到日志工厂,则使用jdk的日志工厂
具体实现类在/struts2-core/xwork/com/opensymphony/xwork2/util/logging/LoggerFactory.java
对应代码如下:

protected static LoggerFactory getLoggerFactory() {
        lock.readLock().lock();
        try {
            if (factory != null) {
                return factory;
            }
        } finally {
            lock.readLock().unlock();
        }
        lock.writeLock().lock();
        try {
            if (factory == null) {
                String userLoggerFactory = System.getProperty(XWorkConstants.XWORK_LOGGER_FACTORY);
                if (userLoggerFactory != null) {
                    try {
                        Class clazz = Class.forName(userLoggerFactory);
                        factory = (LoggerFactory) clazz.newInstance();
                    } catch (Exception e) {
                        throw new XWorkException("System property [" + XWorkConstants.XWORK_LOGGER_FACTORY +
                                "] was defined as [" + userLoggerFactory + "] but there is a problem to use that LoggerFactory!", e);
                    }
                } else {
                    try {
                        Class.forName("org.apache.commons.logging.LogFactory");
                        factory = new com.opensymphony.xwork2.util.logging.commons.CommonsLoggerFactory();
                    } catch (ClassNotFoundException ex) {
                        //commons-logging not found try slf4j LogFactory
                        try {
                            Class.forName("org.slf4j.LoggerFactory");
                            factory = new Slf4jLoggerFactory();
                        } catch (ClassNotFoundException cnfex) {
                            // slf4j not found, falling back to jdk logging
                            factory = new JdkLoggerFactory();
                        }
                    }
                }
            }
            return factory;
        } finally {
            lock.writeLock().unlock();
        }
    }

对于这个类中的代码,我觉得有2点值得学习。其一:对于涉及I/O的操作使用读写锁;其二:对于程序运行时各种状况的预判,使得代码鲁棒性更好。
使用ReentrantReadWriteLock这个读写锁的实现非常简单:

private static final ReadWriteLock lock = new ReentrantReadWriteLock();

public void readOperation() {
  lock.readLock().lock();
  try {
    // some read operation...
  }
  finally {
    lock.readLock().unlock();
  }
}

public void writeOperation() {
  lock.writeLock().lock();
  try {
    // some write operation...
  }
  finally {
    lock.writeLock().unlock();
  }
}

一般在处理多线程互斥资源的时候首先会想到synchronized这个关键字,使用它修饰方法或是将操作放到synchronized代码快里面。这里使用ReentrantReadWriteLock的好处是:1.ReentrantReadWriteLock更加面向对象;2.当资源被大量并发读取,却偶尔被修改的情况下,使用synchronized是有性能问题的,因为不管你是读还是写,都要锁。而ReentrantReadWriteLock却不然。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值