构建门户之利刃Liferay Portal系统架构
传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
1How to Access Protal(Simple)
用户可以通过传统上网或者无线上网的方式来访问Protal。而开发人员可以通过SOAP、RMI和自定义的通道类来访问暴露给外部调用的API来操作Protal。
2Protal Interface(JSP168)
Liferay被设计成能够部署符合Portlet应用接口(JSP168)标准的Portlet。另外,很多有用的Portlet(例如邮件、文档、日历、公告栏等)都已经与Portal绑定,而且可以把它们作为添加自定义Portlet的范例。
3Struts and Tiles(Representation Tier)
所有HTTP和WAP请求都通过MainServlet响应,MailServlet扩展了Struts基类ActionServlet。 MainServlet处理所有的请求,使得每个请求都能够转发到合适的PortletAction进行处理。更多有关Portal的web框架请参考Apache软件基金会的核心项目--Struts。 Portal的布局信息通过定制的模板管理。更多有关Tiles如何管理布局的议题请参考Tile的相关文档。
4Session EJBs、Spring and Hibernate(Biz and Persistence Tier)
Liferay不再依赖EJB,可以部署在标准的Servlet容器中。所有的业务逻辑都集中在可以被Spring查找和实例化的POJO中实现。这些实现都可以通过Spring的AOP和IOC修改或者强化。
Portal专业版调用POJO实现,以提供轻量级的一致外观。所有的数据都使用Hibernate持久化,以供POJO实现调用。 Liferay原先是使用CMP技术构建持久化, 但是考虑到Hibernate在持久化数据方面,具有速度和弹性的优越性,因此转为使用Hibernate进行构建。 Liferay不依赖特定的数据库,可以在多种方言的数据库上运行。
Liferay使用JAAS Web安全机制。当用户登录的时候,用户信息会被传送到相应的Servlet和EJB节点。远程的Session EJB正是利用这一点,在EJB层确认安全性和进行授权,防止它在别处被复制。本地Session EJB向其他Session EJB暴露业务逻辑,不再需要显式地确认安全性,因为它们不会被远程调用。信息也会被传送到远程Session EJB的POJO中实现。
Portal 企业版使用Session EJB封装POJO实现,为大型网站提供重量级扩展和事务支持。它允许开发人员将Web服务器、EJB服务器、数据库服务器三者分开,构建自己的三层架构。这是真正的N层部署,因为没有人再关注单层,而且为企业实现了弹性的最大化。大多数的EJB、HBM和Model都是由/portal-ejb目录下service.xml文件中antbuild-service生成的。每个持久化数据的Portlet都有属于自己的service.xml。(搜索/portal-ejb目录,将会得到一个列表)。当我们需要为Portlet产生持久类的时候,就可以复制这些文件到/portal-ejb目录下。这是一个构建在Xdoclet引擎上面的内部工具。
例如,在读取Bookmarks Portlet的service.xml时,下列模型类将被生成。每个模型类映射数据库中一张表。无需编辑BookmarksEntryModel,而是通过编辑BookmarksEntry来增加手工维护的代码。一次性生成BookmarksEntry,扩展了BookmarksEntryModel。使开发人员既能轻松地生成代码,又具备手工维护代码的弹性。
com.liferay.portlet.bookmarks.model.BookmarksEntry com.liferay.portlet.bookmarks.model.BookmarksEntryModel com.liferay.portlet.bookmarks.model.BookmarksFolder com.liferay.portlet.bookmarks.model.BookmarksFolderModelHibernate为各个模型类生成数据关系映射。
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryHBM com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderHBM添加、删除、更新、查找、移动和计算Hibernate entries的持久方法作为默认的持久化机制被生成。
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryPersistence com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderPersistence生成的帮助类调用持久化方法。默认的帮助类调用Hibernate持久化方法来更新数据库。可以在portal.properties文件中进行重写,而且只要扩展了默认的持久化类就可以设置自己的持久化类。这意味着可以自定义在哪里保存你的数据。它可以是一个传统的数据库,或者LDAP服务器等。
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryUtil com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderUtilPool被创建成最小的对象,行为也可以在portal.properties文件中进行修改。
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryPool com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderPool扩展了PrincipalBean的POJO实现持有业务逻辑,确认调用者信息,支持远程访问。调用getUserId()方法返回当前用户Id。调用getUser()方法返回当前用户的模型类。扩展POJO实现的Session EJB实现了PrincipalSessionBean。
比如,这些类允许你删除一个书签入口或者文件夹,当且仅当你是这个入口或者文件夹的创建者。 这些类只有在它们不存在的时候才能被生成。
com.liferay.portlet.bookmarks.service.impl.BookmarksEntryServiceImpl com.liferay.portlet.bookmarks.service.impl.BookmarksFolderServiceImpl帮助类是基于POJO实现生成的。它们提供保存开发人员的时间和错误显示(polluted)的代码。与其写好几行代码来寻找合适的Session EJB包装或者POJO实现,不如简单使用BookmarksEntryServiceUril的addEntry()方法来调用BookmarksEntryServiceImpl。 BookmarksEntryServiceUril 调用BookmarksFolderServiceFactory工厂类来查找实现BookmarksEntryService类。BookmarksFolderServicesFactory根据Spring和portal.properties文件中的配置来决定是否加载Session EJB包装或者POJO实现。Session EJB扩展了POJO实现。
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceHome com.liferay.portlet.bookmarks.service.spring.BookmarksEntryService com.liferay.portlet.bookmarks.service.spring.BookmarksEntryServiceFactory com.liferay.portlet.bookmarks.service.spring.BookmarksEntryServiceUtil com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceHome com.Liferay.portlet.bookmarks.service.spring.BookmarksFolderService com.Liferay.portlet.bookmarks.service.spring.BookmarksFolderServiceFactory com.Liferay.portlet.bookmarks.service.spring.BookmarksFolderServiceUtil通道化设计使得开发人员可以通过80端口调用POJO实现。
com.liferay.portlet.bookmarks.service.http.BookmarksEntryServiceHttp com.liferay.portlet.bookmarks.service.http.BookmarksFolderServiceHttpSoap被生成,以便开发者通过80端口调用POJO实现。Soap比Tunneling还要慢,因为Tunneling请求流是二进制格式的。但是Soap要比Tunneling灵活,因为客户端类不局限于Java。
com.liferay.portlet.bookmarks.service.http.BookmarksEntryServiceSoap com.liferay.portlet.bookmarks.service.http.BookmarksFolderServiceSoap没有扩展PrincipalBean的POJO实现类用来持有业务逻辑,无需确认调用者的信息,可以被本地调用。这些类的存在使得业务逻辑可以很容易的被其他工程集成。这些类只有在先前不存在的情况下才会被生成。
com.liferay.portlet.bookmarks.service.impl.BookmarksEntryLocalServiceImpl com.liferay.portlet.bookmarks.service.impl.BookmarksFolderLocalServiceImpl另外,一些帮助类也会一并生成。
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceHome com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalService com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalServiceFactory com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalServiceUtil com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceHome com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalService com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalServiceFactory com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalServiceUtil因为有些用户需要远程调用本地的Service类,所以远程Service类的本地副本也将被一并生成。
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceHome com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteService com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteServiceFactory com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteServiceUtil com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceEJB com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceEJBImpl com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceHome com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteService com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteServiceFactory com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteServiceUtil很多人会刻意避免使用Session EJB,因为它是重量级的,而且需要大量的编码。我们的构建脚本证明,你可以在复用中保持Session EJB的优势,这样就能很好的达到在付出和回报上的平衡。Spring赋予Liferay额外的弹性。 开发人员在一个Servlet容器中可以使用Liferay Portal测试他们的POJO实现;而对于Liferay Portal企业版,可以支持在一个应用服务器部署成产品。
5SAOP、RMI and Tunneling
所有的远程POJO实现都通过SOAP、RMI和我们自己的Tunneling类暴露给外部世界。 我们之所以简单的这样做,并不是因为Web Service还是一个混沌的世界,而是由于我们发现它对系统集成很有帮助。下面是一个公司在平衡这些资源方面的实施方案。 3 sixteen是一家将快速创建和运作的T恤公司。他们看到Liferay,想利用集成购物Portlet。但是他们觉得Liferay作为一个处于时尚前沿的T恤公司站点实在是太难看了。为了解决这个问题,他们决定将网站分为两个站点:一个手册站点和一个购物站点。www.3sixteen.com成为一个构建在Flash上的漂亮的站点,my.3sixteen.com则是使用Liferay分发的购物站点,这两个站点分别部署在不同的Linux服务器上。 他们还需要构建一个邮件列表来收集所有感兴趣的客户的邮件地址。为了达到目的,他们又在Flash站点增加了一个JSP弹出窗口,以通知Portal服务器将该邮件地址添加到Address Book
Portlet中的联系列表。
那么显示3sixteen的用户如何利用ABContactServiceHttp增加一个联系列表呢?
ABContactServiceHttp调用ABContactServiceUtil的addContact。通过80端口发送,由http://my.3sixteen.com/tunnel/servlet/AuthTunnelServlet接收。应用服务器确认认证是否匹配,然后处理ABContactServiceUtil,感觉就像ID为joe_bloggs的用户在调用addContact一样。最终ABContactServiceUtil调用ABContactServiceImpl来完成实际工作。
现在Joe Bloggs可以登录到portal,在Address Book portlet可以看到他已经有一个新的联系列表。所有被包含的portlet都有这个性能因为这些帮助类已经生成。这意味着你可以撰写applet或者任何Java应用来操作那些包含你的业务逻辑的Session EJB。假如有人持有你的密码那么这将是一个安全隐患,你可以通过修改配置文件portal.properties让Tunnel Servlet只监听特定的端口。另外, 你也可以通过SOAP和RMI操作Session EJB。
6Application Server
Liferay是从底层构建的,可以被应用服务器所调用。下面是一个Portal范例列表,显示Portal连接数据库以及展示Liferay的性能。http://demo.liferay.net
http://my.ccuc.net
http://my.3sixteen.com
http://portal.liferay.com
http://www.gatewayfriends.org
http://www.jasonandiris.com
每个Portal中的用户都没有在其他Portal中保留信息。他们以域名分隔开,由公司编号存在于各自的空间内。查看Multiple Portal获取细节信息,了解如何在一台机器上部署多个Portal实例。
String URL = "http://my.3sixteen.com"; HttpPrincipal httpPrincipal = new HttpPrincipal(URL, "joe_bloggs", "password"); ABContactServiceHttp。addContact(httpPrincipal, firstName, lastName, emailAddress);