今天是我要记录javaweb框架的最后一篇文章了,后面的内容主要是利用其他的一些开源中间件来完成一些功能,所以想了解后面的内容可以看从零开始写javaweb框架这本书,这本书非常的好。我基本也是按着这书一步一步的做的,只是有时候需要自己再进行一个梳理。
今天讲的是在AOP中添加事务。我们主要针对Service层中带有Transaction方法进行事务控制。
事务控制结合AOP是非常简单的,只不过在处理Service方法的前后添加事务的控制而已,但是有两个点需要注意的是
- 每个线程不可以共享同一连接,否则线程1可能关闭线程2的连接,导致线程2的连接报错。
- 在目前的AOP框架中是无法实现调用Servlet的API的,如果需要使用就必须要将request和response对象传递给Controller中的Action方法,这必然会增加Controller和Servlet API之间的耦合。
我们现在来写事务控制的代理类,再慢慢来解决上面两个问题。
public Object doProxy(ProxyChain proxyChain) throws Throwable {
Object result;
boolean flag = FLAG_HOLDER.get();
Method method = proxyChain.getTargetMethod();
if(!flag && method.isAnnotationPresent(Transaction.class)){
FLAG_HOLDER.set(true);
try {
DatabaseHelper.beginTransaction();
LOGGER.debug("begin tranaction");
result = proxyChain.doProxyChain();
DatabaseHelper.commitTransaction();
LOGGER.debug("commit tranaction");
} catch (Exception e) {
DatabaseHelper.rollbackTransaction();
LOGGER.debug("rollback tranaction");
throw new RuntimeException();
}
}else{
result = proxyChain.doProxyChain();
}
return result;
}
FLAG_HOLDER是保存在ThreadLocal中的布尔变量,保证同一线程中事务控制相关逻辑只会执行一次。这个代理类非常的简单,现在我们来解决第一个问题--连接共享问题
使用ThreadLocal存放连接,保证每个线程有自己独立的连接副本。使用静态块来进行初始化即可。
//使用ThreadLocal 存放连接,保证每个连接有自己独立的连接
private static final ThreadLocal<Connection> CONNECTION_HOLDER;
static {
CONNECTION_HOLDER = new ThreadLocal<Connection>();
}
我们来解决第二个问题,我们将request、response、session等对象进行封装,并提供一些常用的Servlet API并在DispatcherServlet中进行初始化,如此一来整个框架都可以使用基础的Servlet API方法。
/**
* 每个线程拥有一份ServletHelper实例
*/
private static final ThreadLocal<ServletHelper> SERVLET_HELPER_HOLDER =
new ThreadLocal<ServletHelper>();
private HttpServletRequest request;
private HttpServletResponse response;
public ServletHelper(HttpServletRequest request,
HttpServletResponse response) {
this.request = request;
this.response = response;
}
//......其他常用方法的调用
在这几节中,我主要是对从零开始写javaweb框架里面几个我自己没看懂觉得需要梳理的地方进行了大致的梳理!如果你有地方没看懂可以看一下那本书,书里面有不懂的也欢迎留言来探讨一下~~~