CDI技术第三步,对话作用域

对话作用域

对话作用域需要用到一个很关键的接口,javax.enterprise.context.Conversation

默认情况下,对话作用域是跟RequestScope一样的,也就是来一个HTTP请求,就新建一个对象。请求结束,对象也终结了。

那么要如何才能传给下一个请求呢?

需要做两件事情

将对话设置为开始,也就是对话状态由临时对话设置为长时间对话。

这个需要调用javax.enterprise.context.Conversatio.begin()方法,这个方法还可以提供一个对话ID,不过容器会自动生成ID,默认是递增的,由1开始往上加。

在跳转下一个请求时加上请求参数cid,可以是get参数或者是post参数。加上了参数之后,下一个请求就不会新建一个对话了。而且根据ID去对话上下文查找对话。

那么如何结束对话呢?虽然说不带cid参数,对话就不会传递过去,但是对话不结束就会一直占据系统资源,造成内存的浪费。结束对话使用javax.enterprise.context.Conversation.end方法。

我们来写一个简单的demo实验一下。这个demo是这样的,有两个URL,在第一个URL生成的页面中提供一个链接跳到第二个URL,第二个URL关闭对话。

那么我们来写代码吧。

首先是接口。

package cdiscope;

 

public interface ConversationService {

 

void beginConversation();

 

void endConversation();

 

}

其次实现类

package cdiscope;

 

import java.io.Serializable;

 

import javax.enterprise.context.Conversation;

import javax.enterprise.context.ConversationScoped;

import javax.inject.Inject;

import javax.inject.Named;

 

@Named

@ConversationScoped()

public class ConversationServiceBean implements ConversationService, Serializable {

 

private static final long serialVersionUID = 1L;

@Inject

private Conversation conversation;

 

@Override

public void beginConversation() {

if (conversation.isTransient()) {

conversation.begin();

}

}

 

@Override

public void endConversation() {

if (!conversation.isTransient()) {

conversation.end();

}

}

}

然后是两个servlet

package cdiscope;

 

import java.io.IOException;

 

import javax.enterprise.context.Conversation;

import javax.inject.Inject;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

@WebServlet("/conversation1.html")

public class Conversation1Servlet extends HttpServlet {

 

private static final long serialVersionUID = 1L;

@Inject

private ConversationServiceBean conversationService;

@Inject()

private Conversation conversation;

 

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

conversationService.beginConversation();

System.out.println("In servlet " + conversation);

resp.getWriter().append("<html><body>The service is " + conversationService)

.append(".<br/><a href=\"conversation2.html?cid=").append(conversation.getId())

.append("\">Next</a></body></html>");

}

 

}

可以看到这个servlet中将cid参数传递给了下一个servlet

第二个servlet代码

package cdiscope;

 

import java.io.IOException;

 

import javax.inject.Inject;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

@WebServlet("/conversation2.html")

public class Conversation2Servlet extends HttpServlet {

 

private static final long serialVersionUID = 1L;

@Inject

private ConversationServiceBean conversationService;

 

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

conversationService.endConversation();

 

resp.getWriter().append("<html><body>The service is " + conversationService)

.append(".<br/><a href=\"conversation1.html\">Back</a></body></html>");

}

 

}

可以看到这个servlet把对话结束了。

那么我们运行一下看看结果:

第一次请求

 CDI技术第三步,对话作用域_第1张图片

然后跳到第二个请求,可以看到对象的内存地址并没有改变。

 CDI技术第三步,对话作用域_第2张图片

再点击Back跳回来,由于已经结束了对话,所以内存地址已经变了。

 CDI技术第三步,对话作用域_第3张图片

可以这样理解,对话作用域范围介于sessionrequest之间,那么它的实用价值在哪呢?

比如我们做一个复杂的注册应用。

注册分三步或者四步甚至更多,保存在request里肯定不科学,如果保存在页面的隐藏域也并不太好。因为如果我要后退修改前一步的操作呢?势必要写相当复杂的代码。

如果存在session里,到最后要一个个地去清除session保存的对象。这个时候如果用对话作用域,简单省事,提高了开发效率,代码也容易维护。

你可能感兴趣的:(bean,技术,CDI,对象,J2EE)