Liferay 6使用公共服务生成器层出现错误 - BeanLocatorException - 未设置BeanLocator。

10
我们正在尝试将liferay service builder用作所有门户的公共层。我们创建了一个单独的通用portlet项目,在其中使用service.xml构建服务。这会为我们生成一个service.jar文件。我们将此jar复制到所有portlet的WEB-INF/lib目录中。
当我们运行portlet时,日志会抛出以下错误,并在portlet上显示“Portlet暂时不可用”消息。
14:43:17,447 ERROR [jsp:154] com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set
    at com.liferay.portal.kernel.bean.PortletBeanLocatorUtil.locate(PortletBeanLocatorUtil.java:40)
    at com.cogs.common.service.CourseLocalServiceUtil.getService(CourseLocalServiceUtil.java:223)
    at com.cogs.common.service.CourseLocalServiceUtil.getCoursesCount(CourseLocalServiceUtil.java:187)
    at org.apache.jsp.jsps.course.course_005fview_jsp._jspService(course_005fview_jsp.java:542)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)

我确定这种方法应该可以无缝使用。但是在liferay论坛上找到了一些人抱怨它,但还没有找到任何解决方案。如果您找到了一种使用服务构建器作为公共层并且它适用于您的方法,请告诉我们。

我们使用maven构建所有门户项目。

Liferay版本是6.0.5,我们正在使用Spring Portlet MVC进行门户开发。


还没有回答吗?我很惊讶竟然没有人使用通用服务构建器?如果您使用ServiceBuilder,那么您是如何使用它的? - Kzvi
就我个人而言,我使用服务构建器仅为一个门户创建服务;如果需要多个门户使用某些服务,我将所有门户放在同一个项目/WAR中。然而,我认为实现您想要的也不是不可能的。我希望您已经得到了答案,因为我也很好奇 :) - brandizzi
我们正在从Liferay 5.2.3升级到6.0.6GA,我们已经在ext/环境中广泛使用了service builder。我们正在尝试将我们的ext/转换为ext-plugin,并且在此过程中,我正在尝试找到一种解决端口之间共同服务层的好方法,因为看起来他们将在未来版本中弃用ext-plugins中的service builder。我也很惊讶,目前还没有一个好的答案来解决这个问题。 - Jeff
我们尝试了几个选项,最终决定不使用常见的服务生成器层,因为它变得过于复杂。如果您正在尝试一些选项,这可能有所帮助。我们尝试将服务构建器保留为单独的Portlet,但也没有奏效。Bean Locator可能与Spring版本相关。 - Kzvi
在Eclipse中配置Tomcat后,尝试清理并发布到配置的服务器上。 - Shivam Aggarwal
10个回答

3

我尝试了页面上写的所有方法,但都没有起作用,直到我在pom中为maven插件名称添加了项目版本。

            <configuration>
                <autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
                <appServerDeployDir>${liferay.app.server.deploy.dir}</appServerDeployDir>
                <appServerLibGlobalDir>${liferay.app.server.lib.global.dir}</appServerLibGlobalDir>
                <appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>
                <liferayVersion>${liferay.version}</liferayVersion>
                <pluginType>portlet</pluginType>
                <pluginName>${project.artifactId}-${project.version}</pluginName>
            </configuration>

并且在 liferay-plugin-package.properties 文件中:

   artifactId-version-deployment-context=artifactId-version

例如:

举个例子:

   portlet-sample-1.0-deployment-context=portlet-sample-1.0

查询条件为 artifactId = portlet-sample,version = 1.0。

在构建服务并重新部署war后,我找到了解决方案。

我通过调试com.liferay.portal.kernel.bean.PortletBeanLocatorUtil找到了答案。

BeanLocator beanLocator = getBeanLocator(servletContextName);

被称为“which”的函数总是返回null,没有版本号...

我希望有人能帮助解决这个问题。


3

您需要构建并部署(Portlet-Hook)以满足当前门户所需,您可以在 liferay-plugin-package.properties 文件中查看其名称:

required-deployment-contexts=[Portlet-Hook name]

2
我们有一个类似的需求:有一个portlet(比如说Source-portlet),其他portlet需要使用它的服务。
因此,我们将生成的sourceportlet-service.jar从Source-portlet的WEB-INF/lib移动到{tomcat_home}/lib/ext文件夹中,那里有像portlet-service.jar等其他jar文件。
这种方法的缺点是每当Source-portlet发生变化时,我们都需要重新启动服务器。
如果其他portlet是您的自定义插件portlet,则另一种方法是将生成的sourceportlet-service.jar复制到其他portlet的WEB-INF/lib中。如果您在JSP hook中使用服务,则此方法不起作用。
希望这能帮到您。

2

我曾经苦于找不到解决这个错误的方法,所以我会分享我们的解决方案。端口小部件的名称已更改,构建了服务,但运行端口小部件时仍出现相同的错误:

com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set for servlet context

在我们的情况下,我们需要从../docroot/WEB-INF/lib/portlet-service.jar中删除jar文件。

1

Martin Gamulin的先前答案是正确的。如果您有两个单独的Web应用程序,一个用于Spring门户,另一个使用Service Builder(这似乎是在Liferay中执行操作的正确方法),那么您需要确保在初始化期间,您的Spring门户不参考您的ServiceBuilder类。

如果它们这样做,那么根据应用服务器实例化Web应用程序的顺序(在Tomcat中无法指定启动顺序),每次端口let Web应用程序在构建器Web应用程序之前部署时都会发生BeanLocatorException。

在我们的情况下,这意味着将 XxxLocalServiceUtil.createXxx(0) 的调用从控制器的构造函数移动到相关方法。


1
我在进行maven门户网站开发时遇到了类似的问题。首先我创建了门户网站,然后再添加service.xml。
问题是生成器寻找的门户网站名称不存在,我通过明确指定我想要生成器查找的门户网站名称来解决了这个问题。
特别地,为了做到这一点,必须使两个pom节点相等: project.artifatctId =(liferay为此创建了一个bean定位器)
和 project.build.(liferay plugin).configuration.pluginName = 生成器的内部门户网站名称
例如,以下是我的pom.xml的一个小片段。
<modelVersion>4.0.0</modelVersion>
<groupId>io.endeios</groupId>
<artifactId>ShowTheCats-portlet</artifactId><!-- ONE -->
<packaging>war</packaging>
<name>ShowTheCats Portlet</name>
<version>1.0-SNAPSHOT</version>
<build>
    <plugins>
        <plugin>
            <groupId>com.liferay.maven.plugins</groupId>
            <artifactId>liferay-maven-plugin</artifactId>
            <version>${liferay.maven.plugin.version}</version>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>build-css</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
                <appServerDeployDir>${liferay.app.server.deploy.dir}</appServerDeployDir>
                <appServerLibGlobalDir>${liferay.app.server.lib.global.dir}</appServerLibGlobalDir>
                <appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>
                <liferayVersion>${liferay.version}</liferayVersion>
                <pluginType>portlet</pluginType>
                <pluginName>ShowTheCats-portlet</pluginName><!-- TWO -->
            </configuration>
        </plugin>

ONE 和 TWO 必须相同


你终于结束了两天的重构工作。非常感谢。在我的情况下,服务生成是在不同的模块中完成的,而不是在门户中完成的,因此设置“pluginName”至关重要。这里,接受我的点赞。 - Patrick Bergner

0

由于您正在使用Maven,请确保您的WAR名称与门户项目名称相同。 调试后,我发现ClpSerializer定义了_servletContextName,它等于WAR项目的<artifactId>。如果您部署名为artifactId-1.0.0-snapshot.war的构件,则将创建该名称的上下文,但是由servicegen生成的代码期望它为artifactId。请通过您的ClpSerializer进行验证。


0
我也遇到了同样的问题。我将以下代码放置在使用common portlet服务层的portlet的liferay-plugin-package.properties文件中。这对我有用。
required-deployment-contexts=common-portlet
最好将service.jar文件复制到tomcat/lib/ext而不是所有portlet的WEB-INF/lib。

0
我的Spring Portlet中的BeenLocator的问题是,我的Portlet的Spring上下文在Liferay的Spring上下文之前被初始化了。
我正在构造函数中使用ClassName className = ClassNameLocalServiceUtil.getClassName(JournalArticle.class.getName());。由于Liferay的上下文没有加载,因此出现了错误。我将该代码段移动到仅在第一次请求需要时调用它的地方。问题得到了解决。
因此,在初始化您的Portlet期间不要依赖Lifery,对生命周期进行某种“延迟”依赖关系的绑定。

0
我采取了以下措施来解决上述问题:
  1. 在pom.xml中设置插件配置属性pluginName为正确的上下文

        <plugin>
            <groupId>com.liferay.maven.plugins</groupId>
            <artifactId>liferay-maven-plugin</artifactId>
            <version>${liferay.version}</version>
            <configuration>
                <autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
                <appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>
                <liferayVersion>${liferay.version}</liferayVersion>
                <pluginType>portlet</pluginType>
                <pluginName>XXXX-portlet</pluginName>
            </configuration>
        </plugin>
    
  2. 可选地,在liferay插件属性文件或portlet.properties文件中设置XXXX-portlet-deployment-context属性

XXXX-portlet-deployment-context=XXXX-portlet

  1. 重新构建服务
  2. 验证生成的ClpSerializer.java是否包含正确的上下文

` public static String getServletContextName() { if (Validator.isNotNull(_servletContextName)) { return _servletContextName; }

    synchronized (ClpSerializer.class) {
        if (Validator.isNotNull(_servletContextName)) {
            return _servletContextName;
        }

        try {
            ClassLoader classLoader = ClpSerializer.class.getClassLoader();

            Class<?> portletPropsClass = classLoader.loadClass(
                    "com.liferay.util.portlet.PortletProps");

            Method getMethod = portletPropsClass.getMethod("get",
                    new Class<?>[] { String.class });

            String portletPropsServletContextName = (String) getMethod.invoke(null,
                    "XXXX-portlet-deployment-context");

            if (Validator.isNotNull(portletPropsServletContextName)) {
                _servletContextName = portletPropsServletContextName;
            }
        } catch (Throwable t) {
            if (_log.isInfoEnabled()) {
                _log.info(
                    "Unable to locate deployment context from portlet properties");
            }
        }

        if (Validator.isNull(_servletContextName)) {
            try {
                String propsUtilServletContextName = PropsUtil.get(
                        "XXXX-portlet-deployment-context");

                if (Validator.isNotNull(propsUtilServletContextName)) {
                    _servletContextName = propsUtilServletContextName;
                }
            } catch (Throwable t) {
                if (_log.isInfoEnabled()) {
                    _log.info(
                        "Unable to locate deployment context from portal properties");
                }
            }
        }

        if (Validator.isNull(_servletContextName)) {
            _servletContextName = "upay-portlet";
        }

        return _servletContextName;
    }
}`

部署war文件,验证war名称和日志是否正确匹配上下文名称。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接