Jetspeed2 Portal架构及运行机制分析.docx
-
资源ID:4885689
资源大小:189.88KB
全文页数:15页
- 资源格式: DOCX
下载积分:15金币
友情提示
2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
|
Jetspeed2 Portal架构及运行机制分析.docx
项目产品标示及版本_类型标示_文档简称密级JETSPEED2 Portal架构及运行机制分析版本<X.X>All Rights Reserved© yyyy-mm-dd修订历史记录及确认表日期版本阶段说明作者批准人目录一、APACHE门户项目组整体架构1二、JETSPEED 和 SPRING2三、JETSPEED-2工作流程4四、PIPELINE6五、CONTAINER8六、JETSPEED PORTLET 扩展服务9、Apache门户项目组整体架构在分析JETSPEED内核之前,我们有必要了解清楚整个Apache门户项目组的组成项目。其中包 括:Jetspeed-1/2,Bridges,Pluto,WSRP-4J 和 Graffito0Jetspeed-1和Jetspeed-2角色相同,我们接下来所有Jetspeed都是指Jetspeed-2。JEE Web Contaitier(S up ported Servlet 2、3 and above)图1-1 apache门户项目架构图上图中粉红色包围部分为Apache门户项目,其它由土黄色包围部分为它们的依赖项目。通过上图 可以很清楚看到,全部项目都构建在JEE Web Tier上,理论上只要支持Servlet 2.3或以上版本规 范的Web容器,都可以作为Apache门户项目的基础平台,但Jetspeed官方其实仅仅声明Tomcat 是其唯一支持的Web容器。另一块必要的依赖,是构建在O/R mapping项目Apache OJB之上的 数据仓库,用于存放Portal系统信息和用户个性化配置(Profile)oPortals Bridges项目其本质就是由一组类库构成的轻量级框架,通过该桥接器框架可以在门户上支 持众多流行的Web框架,如上图括号中所列举。用户通过它可以很容易的将已有的基于这些流行 Web框架的Web应用程序,通过少量的修改和配置,作为Portlet应用程序发布单元发布到Portal 上。这个项目不但在Jetspeed上取得的成功,还被众多开源的,甚至商用的门户实现所使用,如 JBoss Portal,GridSphere Portal,Stringbeans Portal,Vignette Application Portal,ApacheCocoon Portal 和 Jetspeed PortaloJetspeed项目是整个Apache Portal项目组的核心,它是一个功能完备的,易于扩展的企业级 Portal 实现。Pluto是Jetspeed默认的本地Portlet Container实现,它是一个完全符合JSR-168规范的Portlet 容器实现,其前身为旧M捐赠的源代码,因此我们至今还能够在WebSphere Portal 5.1.1中看到它 的身影。这里要注意本地的意思是指运行在该Portlet容器里的Portlet应用程序在物理上与Portal 在同一个JVM进程中。WSRP-4j是WSRP规范的JAVA实现,它可以提供类似Html IFrame这样速成的内容抓取能力。Graffito是用于构建内容管理应用程序的框架,从它自身的架构设计上来看应该是一个独立平台,但 事实上该项目复用了大量Jetspeed的模块,并且其表现层为发布到Jetspeed上的几个Portlet应用 程序。二、Jetspeed 和 SpringJetspeed架构体系最大特点,也是其高度可订制的根基就是,它选用著名开源POJO框架Spring 作为其底层实现。下图简单描述了目前Jetspeed对Spring的依赖关系:Jetspeed使用到的Spring组件Apache OJB O/R Mappersand the ApplicationContextApache OJB O/R MappersBeans, BeanFactory and the ApplicationContext图2-1Spring FrameworkDeclarative transaction managementBeans BeanFactory and the ApplicationContextJetspeed 主要使用了 Spring 最核心的 IoC 引擎 BeanFactory 和 ApplicationContext,管理所有 Jetspeed Components的生命周期和依赖关系,所有这些组件的Spring声明全部定义在名为assembly的文件夹中的XML文件里。如果第三方开发者认为默认的Jetspeed组件不足以满足要 求,只要按照自己需求编写Jetspeed Component的Interface的实现类,然后修改Spring Bean XML定义,就可以轻易替换掉默认的实现。例如:Jetspeed SearchEngine Component Definition<beans default-lazy-init="false" default-dependency-check="none default-autowire="no"><!-SEARCH COMPONENT-><bean id="org.apache.jetspeed.search.SearchEngine”class="org.apache.jetspeed.search.lucene.SearchEngineImpl” abstract="false”singleton="true" lazy-init="default" autowire="default”dependency-check="default"><constructor-arg index="0”><value>$applicationRoot/WEB-INF/search_index</value></constructor-arg><constructor-arg index="1”><null /></constructor-arg><constructor-arg type="boolean"><value>true</value></constructor-arg><constructor-arg><ref bean="org.apache.jetspeed.search.HandlerFactory" /> </constructor-arg></bean>Jetspeed在实现过程中遵循着面向接口编程的最佳实践,上面中的Bean id为 org.apache.jetspeed.search.SearchEngine,事实上这是一个 SearchEngine 定义在核心 jetspeed- api 组件中的接口,org.apache.jetspeed.search.lucene.SearchEnginelmpl 为该接口的实现类,这 个类定义在components/search组件中,后面的内容就是SearchEngineImpl的构造函数的输入参 数,注意最后一个参数 org.apache.jetspeed.search.HandlerFactory 也是一个 Java Interface 的接 口。Spring在实例化SearchEngine的时候,会首先分析它的构造函数参数是否已经全部满足条件 (实例化),Spring会根据搜索bean id 为 org.apache.jetspeed.search.HandlerFactory 的 bean,如 果已经实例化就直接注入到SearchEngineImpl的构造函数调用里;如果没有就实例化这个bean之 后,再注入。Apache OJB O/R Mappers由于Spring对Apache OJB提供良好的支持,因此Jetspeed中与数据库相关的功能基本上都用过 Spring 的 PersistenceBrokerDaoSupport 实现。这些组件包括:Capablity、 DatabasePageManager、Pipeline、Preferences> Profiler、Registry、Security、SSO 等。O/R Mapping的信息定义在上面这些组件jar包中的JETSPEED-INF/ojb/%component name%_repository.xml文件中,其中%component name%需要用组建名称替代。Declarative transaction management在 Jetspeed 中,它采用 了 Spring 的 declarative transaction 机制,下面一段 XML 定义 了 SSOProvider的事物管理:Declarative Transaction<beans default-lazy-init="false" default-dependency-check="none” default-autowire="no"><!-SSO Implementation-><bean id="PersistenceBrokerSSOProvider”class="org.apache.jetspeed.sso.impl.PersistenceBrokerSSOProvider” init-method="init" abstract="false" singleton="true" lazy-init="default" autowire="default" dependency-check="default"><constructor-arg index="0”><value>JETSPEED-INF/ojb/sso_repository.xml</value> </constructor-arg></bean><beanid="org.apache.jetspeed.sso.SSOProviderparent="baseTransactionProxy” name="ssoProvider" abstract="false" singleton="true" lazy-init="default" autowire="default" dependency-check="default"><property name="proxyInterfaces"><value>org.apache.jetspeed.sso.SSOProvider</value> </property><property name="target"><ref bean="PersistenceBrokerSSOProvider" /></property><property name="transactionAttributes"><props><prop key="addSite*">PROPAGATION_REQUIRED</prop><prop key=HupdateSite*n>PROPAGATION_REQUIRED</prop><prop key="removeSite">PROPAGATION_REQUIRED</prop><prop key="addCredentialsForSite">PROPAGATION_REQUIRED</prop><prop key="updateCredentialsForSite">PROPAGATION_REQUIRED</prop><prop key="removeCredentialsForSite">PROPAGATION_REQUIRED</prop><prop key="setRealmForSite">PROPAGATION_REQUIRED</prop><prop key="*">PROPAGATION_SUPPORTS</prop></props></property></bean></beans>由上图可知,通过Spring的Declarative Transaction机制,Jetspeed很轻易实现了细颗粒度的事物 管理,用户可以很容易配置需要管理事务的方法,如 "addSite*"、"updateSite*"和"removeSg等 等,其中"*"为通配符。三、Jetspeed-2工作流程CcwiTialoldor <iGr-eate JetEpeedPixtaiGontext instencereflisterSInaieton rar PortalOoneict Engine and FlalCcHiiigur-allcin图3-1 Jetspeed工作流程序列图由图3-1可知,Jetspeed Portal从JEE角度来看其实就是一个标准的Web应用程序,只不过在 Servlet 架构上引入了 Component Manager 的概念,然后用 Spring 实现了 ComponentManager 接 口。当Servlet被容器停止时,也会同时关闭SpringComponentManager。Servlet启动完毕后,所 有通过Spring Bean XML定义POJO都被实例化了,除了那些指定了 lazy init属性为true的 Bean0图 3-2 Jetspeed RUNTIME 架构图引擎部分是 Jetspeed-2,而 Container 是 Pluto Portlet Container,Portlet 就是自己写的 Portlet;所以这 张图正好对照 JSR168 中的 PortalPortlet ContainerPortlet 的概念。图3-2描述的的工作流程:1、request 送至 server 后由 JetspeedServlet(org.apache.jetspeed.JetspeedServlet)接 收。JetspeedServlet 通过 Jetspeed(org.apache.jetspeed.Jetspeed)取得 ComponentManager,然后通 过 ComponentManager 取得RequestContextComponent(org.apache.jetspeed.request.JetspeedRequestContextComponent)。2、RequestContextComponent 会针对这个 request 建立一个RequestContext(org.apache.jetspeed.JetspeedRequestContext),并且让这个 request 和新建的 RequestContext能互相参照。3、呼叫 Engine(org.apache.jetspeed.JetspeedEngine)的 service()方法,这个方法会把刚刚建立的 RequestContext传入,这样后面的组件才能使用。4、在service()方法中,Engine会依据request的目标 URL来取得相对应的 Pipeline(org.apache.jetspeed.pipelineJetspeedPipeline)来 处理。Pipeline 使 用 了 chain of responsibility 的 pattern,是由一堆 Valve(org.apache.jetspeed.pipeline.valve.Valve)串起来的。5、各个Valve依序执行,其中某些 Valve会和Container动作,某些Valve会负责产生要 response的portal页面。在这个过程中, Continer会执行相关的 Portlet,并将会吉果返回至 Pipeline,也就是 Valve chain 中。6、将产生的portal页面传回给user,流程结束。四、Pipeline由上面的介绍,应该可以体会到Pipeline在J2中是非常重要的,这里附上Pipeline的官方UML图 做参考。8 JetspeedPipeline«intsrface»O PipelineQ initializeQ addVakefVaLeQ getVal/esQ: Val/eQ in yo k&( Req u estC o ntsxt)日mMsValvetVal岳O nams: Strin g o valves: ValveOcF Jetsp &sd Pip &lin &(Strin g, List =:£>)* initialize setNam&tString) g&tNamst): StringQ MdV日加已(V日”已Q getValves(: ValveOQ rsmD v sVa L e(Va lvQ in vo k&( R&q u estC o nt&xt in vo keN sxtfRsq u estC o ntsxt图4-1 jetspeed-plpelineJetepeed Pipeline'<capab1rtyVlve>- wpcytalURLMwI'En. oenwltYVlve>- <locaEatbnVak'e>- passwo'dOedentElVlve>- <loolnVahJa<tDnVelve>< profilerValve>- <oontainerValve>- <actfenValv=>- <agegartErValve>H <clBanLlpVal¥e>图4-2Spring设定都在webappsjetspeedWEB-图4-3Jetspeed-2本身是Spring-based的架构,主要的INFassembly下。JetspeedServlet在init时会建立Spring容器并载入这些xml文件,而之前提到的ComponentManager就可以通过name或class在Spring容器中寻找需要的component。Jetspeed Pipeline实际上就是设计模式中常见的Chain of Responsibility模式(职责链模式)的具 体实现,其设计概念类似 Servlet Filter, 一个封装了 HttpServletRequest 和 HttpServletResponse Object的Context在Pipeline中传递,每个valve都根据自己的需要从HttpServletRequest对象中 获取信息并将处理的结果写入context或HttpServletResponse对象,以传递给后面的valve使用。这些Valve的定义和排序都是通过Spring Bean来配置的,定义文件为pipelines.xml,下面为该文 件片断截取:<bean id="securityValve”class="org.apache.jetspeed.security.impl.SecurityValveImpl” init-method="initialize" abstract="false" singleton="true" lazy- init="default” autowire="default" dependency-check="default"> <constructor-arg><ref bean="org.apache.jetspeed.profiler.Profiler" /> </constructor-arg> <constructor-arg><ref bean="org.apache.jetspeed.security.UserManager" /> </constructor-arg> <constructor-arg><ref bean="PortalStatistics" /></constructor-arg></bean><bean id="jetspeed-pipeline” class="org.apache.jetspeed.pipeline.JetspeedPipeline"init-method="initialize” abstract="false" singleton="true" lazy-init="default" autowire="default” dependency-check="default"> <constructor-arg><value>JetspeedPipeline</value></constructor-arg><constructor-arg><list><ref bean="capabilityValve" /><ref bean="portalURLValve" /><ref bean="securityValve" /><ref bean="localizationValve" /><ref bean="passwordCredentialValve" /><ref bean="loginValidationValve" /><ref bean="profilerValve" /><ref bean="containerValve" /><ref bean="actionValve" /><ref bean="DecorationValve" /><ref bean="aggregatorValve" /><ref bean="cleanUpValve" /> </list> </constructor-arg></bean><bean id="pipeline-map" class="java.util.HashMap" abstract="false” singleton="true" lazy-init="default" autowire="default” dependency-check="default"> <constructor-arg><map><entry key="/portlet"><value>portlet-pipeline</value></entry><entry key="/portal"><value>jetspeed-pipeline</value></entry><entry key="/ajaxapi"><value>ajax-pipeline</value></entry><entry key="/login"><value>jetspeed-pipeline</value></entry><entry key="/fileserver"><value>fileserver-pipeline</value></entry><entry key="/desktop"><value>desktop-pipeline</value></entry><entry key="/action"><value>desktop-action-pipeline</value></entry></map></constructor-arg></bean>上面第一个 BEAN 定义了 Security Valve,第二个 BEAN 定义了名为 JetspeedPipeline 的一个 Pipeline,第三个BEAN定义了这些Pipeline对应的URL Pattern0我们定义自己特有的Pipeline Valve(只需要实现 org.apache.jetspeed.pipeline.valve.Valve 接口,并在这个 xml 文件中定义它), 或者改变现有Pipeline中valve执行顺序,甚至创建新的Pipeline,并把它映射到某个URL Pattern 上。但这里需要注意的是新URL Pattern映射不能跟现有的重复,这是因为映射是通过Map数据结 构实现。让我们回到图3-2,接下来的Container处理由一个竖线分隔,这是由于在Pipeline的 aggregatorValve发生了 cross context dispatch0需要注意的是Valve的实现类并不是线程安全的, 开发者必须自己管理共享变量,最好就是不要定义对象成员变量,全部使用方法内部变量。五、Container这里需要说明Portal并不等价于Portlet Container,一个企业级的门户实现,可以包含或者说支持 多种Portlet Container同时运行,例如 旧M WebSphere Portal就既包含兼容JSR-168规范的 Portlet Container又包含了支持一些旧M特有功能属性的Portlet Container。对于Jetspeed而言,Jetspeed-2完全抛弃Jetspeed-1的架构,只有一个标准的Portlet Container 实现一一Pluto项目,这是一个完全符合JSR168标准的架构。Pluto的设计目标,其实既是一个完整的、自包含的轻量级门户,又是一个易于内置的PortletContainer。它不需要Jetspeed也能够单独工作。Jetspeed所内置的Pluto版本为稳定的1.0.1版。Jetspeed采用了 Servlet规范中的Cross Context Dispatch机制,将之集成了起来,这就是为什么 Runtime架构图上,两者要用竖线分隔开来,因为他们其实是两个完全不同的Web应用,有着不一 样的Context设置,之间通过Cross Context Dispatch机制联系起来的。因此必须注意开启Cross Context Dispatch机制,同时要注意这种使用方式所带来的安全问题。Tomcat下就是通过设置文 件 TOMCAT_ROOT%/conf/Catalina/localhost/jetspeed.xml:<Context path="/jetspeed" docBase="jetspeed" crossContext="true”><RealmclassName="org.apache.catalina.realm.JAASRealm”appName="Jetspeed”userClassNames="org.apache.jetspeed.security.impl.UserPrincipalImplroleClassNames="org.apache.jetspeed.security.impl.RolePrincipalImpl "useContextClassLoader="false" debug="0” /><Resource name="jdbc/jetspeed" auth="Container”factory="mons.dbcp.BasicDataSourceFactory”type="javax.sql.DataSource" username="" password=""driverClassName="org.apache.derby.jdbc.EmbeddedDriver”url="jdbc:derby:/tmp/j2"maxActive="100"maxIdle="30”maxWait="10000” /><ValveclassName="org.apache.catalina.authenticator.FormAuthenticator”characterEncoding="UTF-8” /> </Context>在Pluto和Jetspeed相互配合下,通过JetspeedContainerServlet,最终执行控制权会交给Portlet 的实现类。JetspeedContainerServlet就定义在Portlet应用程序所属的Web应用单位中,也就是说 所有在Jetspeed中运行的Portlet Web应用都必须在Web.xml中包含JetspeedContainerServlet的 定义。在Tomcat中,这是通过deploy-tool组件完成的,包含:<servlet><servlet-name>JetspeedContainer</servlet-name><display-name>Jetspeed Container</display-name><description>MVC Servlet for Jetspeed PortletApplications</description><servlet-class>org.apache.jetspeed.container.JetspeedContainerServlet</servlet-class><init-param><param-name>contextName</param-name><param-value>rss</param-value></init-param><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>JetspeedContainer</servlet-name><url-pattern>/container/*</url-pattern></servlet-mapping><taglib><taglib-uri><taglib-location>/WEB-INF/tld/portlet.tld</taglib-location> </taglib>六、Jetspeed Portlet 扩展服务Jetspeed 为 Portlet 应用提供了 Jetspeed Service 架构,用以服务 Portlet。JSR-168 并没有对 Portlet开发提供任何特别的支持,它仅仅是SERVLET 2.3规范的一个扩展,因而每家Portal厂商 都提供了自己的扩展。Jetspeed提供的扩展方式跟很多厂商对 Servlet规范的扩展一样,定义了一个名为 jetspeed- portlet.xml的文件,作为标准的portlet.xml的扩展。只要你在打包发布portlet应用时将这个文件与 portlet.xml放在一起,Jetspeed的发布程序就会自动读取这个文件,并根据其内容执行一系列的操 作。下面我们来看看这个文件的格式:<portlet-app id="j2-admin" version="1.0”xmlns=" xmlns:js="http:/portals.apache.org/jetspeed” xmlns:dc="http:/www.purl.org/dc"><js:services><<<<<<<<<<<<<<<<<s:service name="ApplicationServerManager" /> s:service name="DeploymentManager" /> s:service name="EntityAccessor" /> s:service name="GroupManager" /> s:service name="PageManager" /> s:service name="PermissionManager" /> s:service name="PortalAdministration" /> s:service name="PortletFactory" /> s:service name="PortalAdministration" /> s:service name="PortletRegistryComponent" /> s:service name="PortalStatistics" /> s:service name="Profiler" /> s:service name="RoleManager" /> s:service name="SearchComponent" /> s:service name="SSO” /> s:service name="UserManager" /> s:service name="HeaderResource" /></js:services></portlet-app>跟据XML Element的名字,可以理解就是提供给j2-admin这个Portlet应用程序使用的一些 Serviceso下面我们来看这些Services是怎么定义的。以UserManager这个服务为例,首先回到前 面提至|过的 assemble 目录下,找到U jetspeed-services.xml 和 security-managers.xml, 下面分别是 它们的内容节选:jetspeed-services.xml<beans default-lazy-init="false" default-dependency-check="none” default-autowire="no"><!-Portlet Services-><bean id="PortalServices”class="org.apache.jetspeed.services.JetspeedPortletServices”abstract="false" singleton="true" lazy-init="default" autowire="default” dependency-check="default"><constructor-arg><map><entry key="SearchComponent"><ref bean="org.apache.jetspeed.search.SearchEngine" /> </entry><entry key="UserManager"><ref bean="org.apache.jetspeed.security.UserManager" /> </entry><entry key="PageManager"><ref bean="org.apache.jetspeed.page.PageManager" /> </entry></map></constructor-arg></bean></beans> security-managers.xml<bean