JSF @SessionScoped Managed Bean - WebLogic群集复制

时间:2018-04-04 13:31:09

标签: jsf weblogic cluster-computing

技术堆栈:

      WebLogic 12.1.3

      JSF 2.1

      Primefaces 6.1

我正在寻求有关如何编码@SessionScoped ManagedBean以在所有集群服务器上进行复制的建议。

我的假设是,一旦SessionScoped,一个对象应该在所有集群服务器上复制,所有属性都是当前值。

在迁移到集群WebLogic平台时,我正在测试当前的JSF应用程序是否会在集群中的所有服务器上携带Session值。我的测试结果是失败了。然后我尝试编写一个简单的应用程序来监视ViewScoped和SessionScoped对象的行为方式。 WebLogic群集配置如下

img0

ManagedServer_1具有IP x.x.x.212并侦听端口7003 ManagedServer_2具有IP x.x.x.212并侦听端口7004 我使用Fiddler来启用端口解析

我正在使用一个简单的单页JSP Web应用程序,我在后面的模型上更新了一个值。 Web应用程序 weblogic.xml中

    <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
      <jsp-descriptor>
        <keepgenerated>true</keepgenerated>
        <debug>true</debug>
      </jsp-descriptor>
      <context-root>/SessionTest</context-root>
      <session-descriptor> 
        <persistent-store-type>replicated_if_clustered</persistent-store-type>
        <debug-enabled>true</debug-enabled> 
      </session-descriptor>
    </weblogic-web-app>

的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
        <context-param>
            <param-name>javax.faces.PROJECT_STAGE</param-name>
            <param-value>Development</param-value>
        </context-param>
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>/faces/*</url-pattern>
        </servlet-mapping>
        <session-config>
            <session-timeout>
                30
            </session-timeout>
        </session-config>
        <welcome-file-list>
            <welcome-file>faces/index.xhtml</welcome-file>
        </welcome-file-list>
        <distributable/>
    </web-app>

的index.xhtml

    <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"         
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://java.sun.com/jsf/facelets"
          xmlns:p="http://primefaces.org/ui">
    <h:head>
     <title>Session Replication Test</title>
    </h:head>
    <h:body>
     <h:form>
        <p:growl id="grw" widgetVar="grw" showDetail="true"/>            
        <p:panel id="panel1" header="Ajax Panel @ ${controller.model.serverIP}:${controller.model.serverPort}">
            <p:inputText id="name_input" value="${model.name}" widgetVar="name_in">
                <p:ajax update="@this"/>
            </p:inputText>
            <br/><br/>
            <p:commandButton id="name_command" value="Call Ajax" actionListener="${controller.updateNameLabel(model.name)}" update="@form"/>
            <br/><br/>
            <p:outputLabel id="name_output" value="Hello ${model.name} * ${model.clicks}"/>
        </p:panel>            
      </h:form>
     </h:body>
    </html>

支持index.xhtml,我们有一个

模型类

    @ManagedBean
    @SessionScoped
    public class Model implements Serializable {

        private String name;
        private int clicks;
        private String serverIP;
        private String serverPort;
    public Model() {
            name = "";
            clicks = 0;
            serverIP = "";
            serverPort = "";
            System.out.println("---------- Model constructor -----------");
    }

      // Emmanuel's suggestion applied here
      private void pushSesssion(){
          HttpSession httpSession = fetchSession();
          httpSession.setAttribute("model", this);
      }

      private HttpSession fetchSession(){
         ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
         HttpSession httpSession = (HttpSession) ec.getSession(false);
         return httpSession;
       }

      … getters and setters

       public void setClicks(int clicks) {
         this.clicks = clicks;
         pushSesssion();
       }
       // Emmanuel's suggestion - End

    }

..和一个

控制器类

    @ManagedBean
    @ViewScoped
    public class Controller implements Serializable {

    @ManagedProperty(value = "#{model}")
    private Model model;

    /**
    * Creates a new instance of Actions
    */
    public Controller() {
    }

    @PostConstruct
    public void init() {
    System.out.println("----------------- Controller initializing @ " + new Date()+" ------------------------");
    fetchIP();
    }

    private void fetchIP() {
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    HttpServletRequest request = (HttpServletRequest) ec.getRequest(); 
    String localIP = request.getLocalAddr();
    int localPort = request.getLocalPort();
    if(!model.getServerIP().equals(localIP) || !model.getServerPort().equals(localPort+"")){
        addFacesMessage(FacesMessage.SEVERITY_INFO,"Server Changed","Please wait 30 seconds before next click.");
        model.setServerIP(localIP);
        model.setServerPort(localPort+"");        
    }
    }

    private HttpSession fetchSession(){
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    HttpSession httpSession = (HttpSession) ec.getSession(false);
    return httpSession;
    }

    public void updateNameLabel(String name) {
    HttpSession httpSession = fetchSession();
    System.out.println("DBG  - "+new Date()+" HttpSession  -- " + httpSession.getId());

    System.out.println("---------------------- DBG 1 -------------------");        
    System.out.println("DBG 1 - model is still local  -- ");
    System.out.println("DBG 1 - HttpSession.model.clicks = " + ((Model)httpSession.getAttribute("model")).getClicks());
    System.out.println("DBG 1 - this.model.clicks = " + model.getClicks());

    model = (Model)httpSession.getAttribute("model");        
    fetchIP();                
    model.setName(name);
    model.setClicks(model.getClicks() + 1);

    System.out.println("---------------------- DBG 2 -------------------");
    System.out.println("DBG 2 - model loaded from httpSession  -- ");        
    System.out.println("DBG 2 - HttpSession.model.clicks = " + ((Model)httpSession.getAttribute("model")).getClicks());
    System.out.println("DBG 2 - this.model.clicks = " + model.getClicks());

    }

在控制器中,我从HTTPSession属性对象和当前对象中打印click值,以确保它是相同的。

运行应用程序:

我使用Fiddler启用端口解析,因为我在开发PC上运行群集,因此只有一个IP可用 在顶部,我列出了我们命中的服务器的IP(x.x.x.212:7003)。

img1

每次点击,Hello XXXX *之后的计数器都会增加。

现在,如果我切换到端口7004并且我希望下一个计数器为4,但它会回到0

enter image description here

以下是服务器的输出

:7003

    ---------- Model constructor -----------
    ----------------- Controller initializing @ Wed Apr 04 09:05:46 EDT 2018 -------
    DBG  - Wed Apr 04 09:05:56 EDT 2018 HttpSession  -- **k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O-!-1996882782!-1285789144!1522847146467**
    ---------------------- DBG 1 -------------------
    DBG 1 - model is still local  -- 
    DBG 1 - HttpSession.model.clicks = 0
    DBG 1 - this.model.clicks = 0
    ---------------------- DBG 2 -------------------
    DBG 2 - model loaded from httpSession  -- 
    DBG 2 - HttpSession.model.clicks = 1
    DBG 2 - this.model.clicks = 1

    DBG  - Wed Apr 04 09:05:57 EDT 2018 HttpSession  -- k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O-!-1996882782!-1285789144!1522847146467

    ---------------------- DBG 1 -------------------
    DBG 1 - model is still local  -- 
    DBG 1 - HttpSession.model.clicks = 1
    DBG 1 - this.model.clicks = 1
    ---------------------- DBG 2 -------------------
    DBG 2 - model loaded from httpSession  -- 
    DBG 2 - HttpSession.model.clicks = 2
    DBG 2 - this.model.clicks = 2

...

    DBG  - Wed Apr 04 09:05:59 EDT 2018 HttpSession  -- k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O-!-1996882782!-1285789144!1522847146467
    ---------------------- DBG 1 -------------------
    DBG 1 - model is still local  -- 
    DBG 1 - HttpSession.model.clicks = 7
    DBG 1 - this.model.clicks = 7
    ---------------------- DBG 2 -------------------
    DBG 2 - model loaded from httpSession  -- 
    DBG 2 - HttpSession.model.clicks = 8
    DBG 2 - this.model.clicks = 8

:7004

    DBG  - Wed Apr 04 09:06:12 EDT 2018 HttpSession  --k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O-!-1285789144!-1996882782!1522847146467
    ---------------------- DBG 1 -------------------
    DBG 1 - model is still local  -- 
    DBG 1 - HttpSession.model.clicks = 0
    DBG 1 - this.model.clicks = 0
    ---------------------- DBG 2 -------------------
    DBG 2 - model loaded from httpSession  -- 
    DBG 2 - HttpSession.model.clicks = 1
    DBG 2 - this.model.clicks = 1

...

    DBG  - Wed Apr 04 09:06:17 EDT 2018 HttpSession  --k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O-!-1285789144!-1996882782!1522847146467
    ---------------------- DBG 1 -------------------

    DBG 1 - model is still local  -- 
    DBG 1 - HttpSession.model.clicks = 11
    DBG 1 - this.model.clicks = 11
    ---------------------- DBG 2 -------------------
    DBG 2 - model loaded from httpSession  -- 
    DBG 2 - HttpSession.model.clicks = 12
    DBG 2 - this.model.clicks = 12

查看会话ID,它似乎是同一个会话

在7003

k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O - ! - !1996882782 -1285789144 1522847146467

在7004

k6yQw2Hd_EKgK7OanKloEHbCKkEMpv9TQfxrXd-8tj05fNlnH8O - ! - !1285789144 -1996882782 1522847146467

,使用JVM Hash镜像

端口7003上的

-1996882782!-1285789144

端口7004上的

-1285789144!-1996882782

但是,模型对象不会被继承,或者在端口更改时重新初始化。

如果您有时间阅读本文,我感谢您的耐心和最终的帮助。

这是Oracle支持部门的回复:

目标:

会话对象属性更改似乎不会在群集中复制。

解决方案:

如果会话对象属性发生更改,请始终使用setAttribute,然后使用内存中复制在对象中复制对象及其属性。

同样,使用removeAttribute从会话对象中删除属性。

0 个答案:

没有答案