使用Grails中的HazelCast进行Web会话复制 - HazelcastSerializationException

时间:2016-02-18 15:08:07

标签: spring grails spring-security hazelcast

我尝试使用Hazelcast docs中给出的grails应用程序中的hazelcast进行会话复制。

Grails版本:1.2.1

Hazelcast:2.5.1(开源版)

我在登录时获得com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver

添加到会话的所有域对象都是序列化的。但org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver来自spring框架。如何从springframework序列化类?。

请帮助您在grails app中正确配置弹簧和弹簧安全性。

启动应用程序时记录:

Running Grails application..
loading security config ...
Feb 18, 2016 9:04:11 PM com.hazelcast.config.UrlXmlConfig
INFO: Configuring Hazelcast from 'jndi:/localhost/WEB-INF/hazelcast.xml'.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Prefer IPv4 stack is true.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Picked Address[192.168.43.68]:5702, using socket ServerSocket[addr=/0.0.0.0,localport=5702], bind any local is true
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Hazelcast Community Edition 2.5.1 (20130427) starting at Address[192.168.43.68]:5702
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Copyright (C) 2008-2013 Hazelcast.com
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTING
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.MulticastJoiner
INFO: [192.168.43.68]:5702 [dev] Connecting to master node: Address[192.168.43.68]:5701
Feb 18, 2016 9:04:12 PM com.hazelcast.nio.ConnectionManager
INFO: [192.168.43.68]:5702 [dev] 57981 accepted socket connection from /192.168.43.68:5701
Feb 18, 2016 9:04:18 PM com.hazelcast.cluster.ClusterManager
INFO: [192.168.43.68]:5702 [dev] 

Members [2] {
    Member [192.168.43.68]:5701
    Member [192.168.43.68]:5702 this
}

Feb 18, 2016 9:04:19 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTED
Server running. Browse to http://localhost:8090/

我登录后即可获得HazelcastSerializationException

堆栈跟踪:

Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
[/].[default][21:04:27,561][http-8090-4] Servlet.service() for servlet default threw exception
com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
    at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
    at com.hazelcast.nio.AbstractSerializer.toByteArray(AbstractSerializer.java:139)
    at com.hazelcast.nio.Serializer.writeObject(Serializer.java:56)
...
Caused by: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
organization.ErrorController[21:04:27,754][http-8090-4] Exception in Controller; Cause=java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, Message=org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, forwardURI=/j_spring_security_check
org.codehaus.groovy.grails.web.errors.GrailsWrappedRuntimeException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
    at java.lang.Thread.run(Thread.java:662)
Caused by: com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
    at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
Process finished with exit code -1

用户域类:

class User implements Serializable {

    def authenticateService

    //domain properties

    boolean isAccessingOwnProfile(){
        User user = authenticateService.userDomain()
        if(user?.id?.toString()?.equalsIgnoreCase(id?.toString())){
            return true
        }else {
            return false
        }
    }
}

有了这个我得到了

com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.grails.plugins.springsecurity.service.AuthenticateService

所以我通过创建AuthenticateService进行了快速修复,如下所示

package com.example
class AuthenticateService extends org.grails.plugins.springsecurity.service.AuthenticateService implements Serializable {
}

在此之后我在QualifierAnnotationAutowireCandidateResolver类中获得相同的异常

配置文件:

/src/templates/war/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <filter>
        <filter-name>hazelcast-filter</filter-name>
        <filter-class>com.hazelcast.web.WebFilter</filter-class>
        <init-param>
            <param-name>map-name</param-name>
            <param-value>my-sessions</param-value>
        </init-param>
        <init-param>
            <param-name>config-location</param-name>
            <param-value>/WEB-INF/hazelcast.xml</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>hazelcast-filter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <listener>
        <listener-class>com.hazelcast.web.SessionListener</listener-class>
    </listener>

    <display-name>/@grails.project.key@</display-name>


    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>@grails.project.key@</param-value>
    </context-param>

    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
    </filter>

    <filter>
        <filter-name>charEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>characterEncodingFilter</param-value>
        </init-param>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>charEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
    </listener>

    <!-- Grails dispatcher servlet -->
    <servlet>
        <servlet-name>grails</servlet-name>
        <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- The Groovy Server Pages servlet -->
    <servlet>
        <servlet-name>gsp</servlet-name>
        <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>gsp</servlet-name>
        <url-pattern>*.gsp</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <!--
        The order of the welcome pages is important.  JBoss deployment will
        break if index.gsp is first in the list.
        -->
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.gsp</welcome-file>
    </welcome-file-list>

    <jsp-config>
        <taglib>
            <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
            <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
            <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>http://www.springframework.org/tags</taglib-uri>
            <taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
            <taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
        </taglib>
    </jsp-config>

</web-app>

/WEB-INF/hazelcast.xml

<?xml version="1.0" encoding="UTF-8"?>
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-2.5.xsd"
           xmlns="http://www.hazelcast.com/schema/config"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <group>
                <name>dev</name>
                <password>dev-pass</password>
        </group>
        <network>
                <port auto-increment="true">5701</port>
                <join>
                        <multicast enabled="true">
                                <multicast-group>224.2.2.3</multicast-group>
                                <multicast-port>54327</multicast-port>
                        </multicast>
                        <tcp-ip enabled="false">
                                <interface>127.0.0.1</interface>
                        </tcp-ip>
                        <aws enabled="false">
                                <access-key>my-access-key</access-key>
                                <secret-key>my-secret-key</secret-key>
                                <!--optional, default is us-east-1 -->
                                <region>us-west-1</region>
                                <!-- optional, only instances belonging to this group will be discovered, default will try all running instances -->
                                <security-group-name>hazelcast-sg</security-group-name>
                                <tag-key>type</tag-key>
                                <tag-value>hz-nodes</tag-value>
                        </aws>
                </join>
                <interfaces enabled="false">
                        <interface>10.10.1.*</interface>
                </interfaces>
                <ssl enabled="false" />
                <socket-interceptor enabled="false" />
                <symmetric-encryption enabled="false">
                        <algorithm>PBEWithMD5AndDES</algorithm>
                        <!-- salt value to use when generating the secret key -->
                        <salt>thesalt</salt>
                        <!-- pass phrase to use when generating the secret key -->
                        <password>thepass</password>
                        <!-- iteration count to use when generating the secret key -->
                        <iteration-count>19</iteration-count>
                </symmetric-encryption>
                <asymmetric-encryption enabled="false">
                        <!-- encryption algorithm -->
                        <algorithm>RSA/NONE/PKCS1PADDING</algorithm>
                        <!-- private key password -->
                        <keyPassword>thekeypass</keyPassword>
                        <!-- private key alias -->
                        <keyAlias>local</keyAlias>
                        <!-- key store type -->
                        <storeType>JKS</storeType>
                        <!-- key store password -->
                        <storePassword>thestorepass</storePassword>
                        <!-- path to the key store -->
                        <storePath>keystore</storePath>
                </asymmetric-encryption>
        </network>
        <partition-group enabled="false"/>
        <management-center enabled="false" update-interval="3" >http://localhost:9999</management-center>
        <executor-service>
                <core-pool-size>16</core-pool-size>
                <max-pool-size>64</max-pool-size>
                <keep-alive-seconds>60</keep-alive-seconds>
        </executor-service>
        <queue name="default">
                <max-size-per-jvm>0</max-size-per-jvm>
                <backing-map-ref>default</backing-map-ref>
        </queue>
        <map name="default">
                <backup-count>1</backup-count>
                <time-to-live-seconds>0</time-to-live-seconds>
                <max-idle-seconds>0</max-idle-seconds>
                <eviction-policy>NONE</eviction-policy>
                <max-size policy="cluster_wide_map_size">0</max-size>
                <eviction-percentage>25</eviction-percentage>
                <merge-policy>hz.ADD_NEW_ENTRY</merge-policy>
        </map>
</hazelcast>

1 个答案:

答案 0 :(得分:0)

异常是因为在实现Serializable接口的域类中注入服务。

我删除了Domain类中的服务注入并尝试登录。 删除依赖项注入后的用户域类

class User implements Serializable {

    // Removed authenticateService injection
    //def authenticateService

    //domain properties

    /*boolean isAccessingOwnProfile(){
        User user = authenticateService.userDomain()
        if(user?.id?.toString()?.equalsIgnoreCase(id?.toString())){
            return true
        }else {
            return false
        }
    }*/
}

并删除了实现Serializable的自定义AuthenticateService。

现在我可以登录1个实例,会话被复制了剩余的实例。