Alfresco 2.0 解讀
Alfresco 2.0 解讀
Alfresco is the Open Source Alternative for Enterprise Content Management (ECM), providing Document Management, Collaboration, Records Management, Knowledge Management, Web Content Management and Imaging.
采用的技術
Java
Spring Aspect-Oriented Framework
ACEGI – Aspect-Oriented Security Framework
MyFaces JSF Implementation
Hibernate ORM Persistence
Lucene Text Search Engine
JLAN
POI File Format Conversion
PDFBox – PDF Conversion
OpenOffice
jBPM
Rhino JavaScript engine
支持的接口
CIFS/SMB Microsoft File Share Protocol
JSR-168 Portlet Specification
JSR-127 Java Server Faces
FTP
WebDAV
Web Services
REST
1、從web.xml開始入手
其它的略過,在 web.xml 中可以看到加載了如下 Spring 配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:alfresco/web-client-application-context.xml
classpath:web-services-application-context.xml
classpath:alfresco/web-api-application-context.xml
classpath:alfresco/application-context.xml
</param-value>
<description>Spring config file locations</description>
</context-param>
alfresco/web-client-application-context.xml
打開它可以看到它引入了所有的 alfresco/web-client*.xml & alfresco/extension/web-client*.xml & jar:*!/META-INF/web-client*.xml
alfresco/web-api-application-context.xml
打開它可以看到它引入了 alfresco/web-api-config.xml & alfresco/extension/web-api-config-custom.xml
web-services-application-context.xml
剛開始找這個文件時,居然沒有找到,怪事!not exist???why?
於是後來才發現這個文件是在 remote-api.jar 包裏,暈,不是很好的做法啊。
bean 配置定義關鍵的文件
<import resource="classpath:alfresco/core-services-context.xml"/>
<import resource="classpath:alfresco/public-services-context.xml"/>
<import resource="classpath:alfresco/model-specific-services-context.xml"/>
<import resource="classpath:alfresco/action-services-context.xml"/>
<import resource="classpath:alfresco/rule-services-context.xml"/>
<import resource="classpath:alfresco/node-services-context.xml"/>
<import resource="classpath:alfresco/scheduled-jobs-context.xml"/>
<import resource="classpath:alfresco/network-protocol-context.xml"/>
<import resource="classpath:alfresco/content-services-context.xml"/>
<import resource="classpath:alfresco/hibernate-context.xml"/>
<import resource="classpath:alfresco/ownable-services-context.xml"/>
<import resource="classpath:alfresco/template-services-context.xml"/>
<import resource="classpath:alfresco/script-services-context.xml"/>
<import resource="classpath:alfresco/index-recovery-context.xml"/>
<import resource="classpath:alfresco/authority-services-context.xml"/>
<import resource="classpath:alfresco/authentication-services-context.xml"/>
<import resource="classpath:alfresco/policy-context.xml"/>
<import resource="classpath:alfresco/import-export-context.xml"/>
<import resource="classpath:alfresco/bootstrap-context.xml"/>
<import resource="classpath:alfresco/workflow-context.xml"/>
<import resource="classpath:alfresco/jcr-api-context.xml"/>
<import resource="classpath:alfresco/avm-services-context.xml"/>
<import resource="classpath:alfresco/audit-services-context.xml"/>
<import resource="classpath*:alfresco/patch/*-context.xml"/>
<import resource="classpath*:alfresco/domain/*-context.xml"/>
<!--
Import all modules and related components.
Extensions are explicitly imported after this so that the default
mechanism can still be used to override module-specific beans.
-->
<import resource="classpath*:alfresco/module-context.xml"/>
<!--
Import of general extensions and bean overrides.
To give developers final control over the tuning
of their own local build, the dev-context.xml file
is processed last (note: dev-context.xml isn't
part of the source tree itself).
For details, see:
https://wiki.alfresco.com/wiki/Developer_Runtime_Configuration
-->
<import resource="classpath*:alfresco/extension/*-context.xml"/>
<import resource="classpath*:alfresco/extension/dev-context.xml"/>
可以看到分層次地進行加載不同的 bean ,並且在後麵提供可擴展的 bean 定義的引入,方便進行擴展,而不需要更變這個配置文件
繼續一個個往下看,並把一些重要的 bean 配置拿出來:
看到配置了 JMX 的服務
<!-- Custom MBeanServer -->
<bean id="alfrescoMBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="${avm.remote.port}"/>
</bean>
<!-- MBeanServer Connector (registers itself with custom alfrescoMBeanServer) -->
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="registry">
<property name="server" ref="alfrescoMBeanServer"/>
<property name="objectName" value="connector:name=rmi"/>
<property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:${avm.remote.port}/alfresco/jmxrmi"/>
<property name="environment">
<map>
<!-- The following keys are only valid when sun jmx is used -->
<entry key="jmx.remote.x.password.file" value="${alfresco.jmx.dir}/alfresco-jmxrmi.password"/>
<entry key="jmx.remote.x.access.file" value="${alfresco.jmx.dir}/alfresco-jmxrmi.access"/>
</map>
</property>
</bean>
<!-- MBeans registered with alfrescoMBeanServer -->
<bean id="VirtServerRegistry"
class="org.alfresco.mbeans.VirtServerRegistry"
init-method="initialize">
JMX 服務暴露
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="alfrescoMBeanServer"/>
<property name="beans">
<map>
<!-- MBeans to register with alfrescoMBeanServer -->
<entry key="Alfresco:Name=VirtServerRegistry,Type=VirtServerRegistry" value-ref="VirtServerRegistry"/>
<entry key="Alfresco:Name=FileServerConfig,Type=FileServerConfig" value-ref="FileServerConfig"/>
</map>
</property>
</bean>
同時暴露了 RMI 的服務
RMI
<!-- The RMI export of the repo remote transport. -->
<bean id="repoRemoteTransportRMI" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service">
<ref bean="repoRemoteTransport"/>
</property>
<property name="serviceInterface">
<value>org.alfresco.service.cmr.remote.RepoRemoteTransport</value>
</property>
<property name="serviceName">
<value>repo</value>
</property>
<property name="registryPort">
<value>${avm.remote.port}</value>
</property>
</bean>
驗證 bean 配置,也是同時暴露了 RMI 的服務
<!-- Here for now. Probably want remote-context.xml file. -->
<!-- The AuthenticationService exported as an RMI service. -->
<bean id="rmiAuthenticationService" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service">
<ref bean="AuthenticationService"/>
</property>
<property name="serviceInterface">
<value>org.alfresco.service.cmr.security.AuthenticationService</value>
</property>
<property name="serviceName">
<value>authentication</value>
</property>
<property name="registryPort">
<value>${avm.remote.port}</value>
</property>
</bean>
avm 裏也暴露了 RMI 的服務
<!-- The RMI wrapper around the AVM remote interface. -->
<bean id="avmRemoteService" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service">
<ref bean="avmRemoteTransport"/>
</property>
<property name="serviceInterface">
<value>org.alfresco.service.cmr.remote.AVMRemoteTransport</value>
</property>
<property name="serviceName">
<value>avm</value>
</property>
<property name="registryPort">
<value>${avm.remote.port}</value>
</property>
</bean>
<bean id="avmSyncServiceTransport" class="org.alfresco.repo.avm.AVMSyncServiceTransportImpl">
<property name="authenticationService">
<ref bean="AuthenticationService"/>
</property>
<property name="avmSyncService">
<ref bean="AVMSyncService"/>
</property>
</bean>
<bean id="avmSyncServiceTransportRMI" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service">
<ref bean="avmSyncServiceTransport"/>
</property>
<property name="serviceInterface">
<value>org.alfresco.service.cmr.remote.AVMSyncServiceTransport</value>
</property>
<property name="serviceName">
<value>avmsync</value>
</property>
<property name="registryPort">
<value>${avm.remote.port}</value>
</property>
</bean>
通過上麵的 JMX 與 RMI 暴露在不同的配置文件裏可以看到,如果我要去掉 JMX 或 RMI 服務的話,需要修改 N 個的配置文件,實在是麻煩。
建議要二次開發時根據需要進行整理,合並到一個文件裏進行暴露即可,或者沒有需要的話就直接 delete 掉這些:)
而且這個 JMX RMI 服務的暴露,導致你不能僅重啟應用就可以,而非得重啟整個應用服務器才行,要不然會報服務已啟動,即默認的端口50500被占用了,而整個應用啟動不了,麻煩。除非你在重啟應用之前再去修改一下配置文件裏的端口號,嗬嗬。
不過,最終的解決辦法是象我在 Jmx4Log4J 裏那樣自己去再封裝一個獲取端口號的類,發現有人用了,就找下一個:)這樣就OK了。
<!-- Datasource bean -->
數據庫連接池用的居然是 org.apache.commons.dbcp.BasicDataSource ,大家自己改吧 c3p0 等等
郵件
<!-- MAIL SERVICE -->
<bean id="mailService" class="org.springframework.mail.javamail.JavaMailSenderImpl">
Lucene 索引和搜索 API
<!-- Indexing and Search API -->
<bean id="indexerComponent" class="org.alfresco.repo.search.IndexerComponent">
<bean id="searchService" class="org.alfresco.repo.search.SearcherComponent">
<!-- Indexer and searchers for lucene -->
<bean id="luceneIndexerAndSearcherFactory"
class="org.alfresco.repo.search.impl.lucene.LuceneIndexerAndSearcherFactory2">
<!-- Indexer and searchers for lucene -->
<bean id="luceneCategoryService" class="org.alfresco.repo.search.impl.lucene.LuceneCategoryServiceImpl">
鎖
<!-- Lock Service -->
<bean id="lockService" class="org.alfresco.repo.lock.LockServiceImpl" init-method="initialise">
版本控製
<!-- Version Service -->
<bean id="versionService" class="org.alfresco.repo.version.VersionServiceImpl" init-method="initialise">
數據庫
<!-- Data Dictionary -->
<bean id="dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="resourceBundles">
<property name="models">
<list>
<!-- System models -->
<value>alfresco/model/dictionaryModel.xml</value>
<value>alfresco/model/systemModel.xml</value>
<value>org/alfresco/repo/security/authentication/userModel.xml</value>
<!-- Content models -->
<value>alfresco/model/contentModel.xml</value>
<value>alfresco/model/bpmModel.xml</value>
<value>alfresco/model/wcmModel.xml</value>
<value>alfresco/model/forumModel.xml</value>
<!-- Content models -->
<value>alfresco/model/applicationModel.xml</value>
<value>alfresco/model/wcmAppModel.xml</value>
<!-- Implementation models -->
<value>org/alfresco/repo/action/actionModel.xml</value>
<value>org/alfresco/repo/rule/ruleModel.xml</value>
<value>org/alfresco/repo/version/version_model.xml</value>
<!-- Deprecated types -->
<value>alfresco/model/deprecated/deprecated_contentModel.xml</value>
</list>
</property>
<property name="labels">
<list>
<value>alfresco/model/dataTypeAnalyzers</value>
<value>alfresco/messages/system-model</value>
<value>alfresco/messages/dictionary-model</value>
<value>alfresco/messages/content-model</value>
<value>alfresco/messages/bpm-messages</value>
<value>alfresco/messages/application-model</value>
<value>alfresco/messages/forum-model</value>
</list>
</property>
</bean>
拷貝
<!-- Copy Service -->
<!-- Note this uses the node service that enforces permissions so you can only copy what you can see -->
<bean id="copyService" class="org.alfresco.repo.copy.CopyServiceImpl" init-method="init">
檢出 / 檢入
<!-- CheckOut/CheckIn Service -->
<bean id="checkOutCheckInService" class="org.alfresco.repo.coci.CheckOutCheckInServiceImpl">
全文搜索
<!-- Bean to support full text search -->
<bean id="LuceneFullTextSearchIndexer"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
Lucene 索引文件備份
<!-- Bean to backup Lucene indexes -->
<bean id="luceneIndexBackupComponent"
class="org.alfresco.repo.search.impl.lucene.LuceneIndexerAndSearcherFactory2$LuceneIndexBackupComponent">
<!-- Registry service -->
<bean id="registryService" class="org.alfresco.repo.admin.registry.RegistryServiceImpl" init-method="init">
<!-- A Simple Filesystem like API for the repo implementation.
Unfinished, experimental, and probably ephemeral. -->
<bean id="repoRemoteService" class="org.alfresco.repo.remote.RepoRemoteService">
<!-- Transactionally wrapped version of above. -->
<bean id="RepoRemoteService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
當中引入了
<import resource="classpath:alfresco/public-services-security-context.xml"/>
使用的是 Acegi 組件,當中引入了
<import resource="classpath:alfresco/cache-context.xml" />
cache-context.xml Cache 相關的,使用的是 EHCache
<bean name="transactionalEHCacheManager" class="org.alfresco.repo.cache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:alfresco/ehcache-transactional.xml</value>
</property>
</bean>
<!-- Service Registry -->
<bean id="ServiceRegistry" class="org.alfresco.repo.service.ServiceDescriptorRegistry"/>
基本上服務都從這裏注入並從中獲取,樹結構,當中有Spring Bean Factory
<!-- File/folder specific service -->
<bean name="fileFolderService" class="org.alfresco.repo.model.filefolder.FileFolderServiceImpl" init-method="init">
<bean name="tempFileMarkerInterceptor" class="org.alfresco.repo.model.filefolder.TempFileMarkerInterceptor">
<!-- Multilingual specific service -->
<bean name="multilingualContentService" class="org.alfresco.repo.model.ml.MultilingualContentServiceImpl">
用 Thread local containing the current action chain
<!-- Action Service -->
<bean id="actionService" class="org.alfresco.repo.action.ActionServiceImpl">
<!-- Rules Service -->
<bean id="ruleService" class="org.alfresco.repo.rule.RuleServiceImpl">
<!-- Rules Aspect -->
<bean id="rulesAspect" class="org.alfresco.repo.rule.RulesAspect" init-method="init">
<!-- Rule triggers -->
<bean id="rule-trigger-base" abstract="true" init-method="registerRuleTrigger">
<!-- Beans pertinent to node persistence and services -->
<!-- Task scheduler -->
<!-- Triggers should not appear here - the scheduler should be injected into the trigger definition -->
<!-- This bean should not need to apear else where in extension configuration -->
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="waitForJobsToCompleteOnShutdown">
<value>true</value>
</property>
<property name="configLocation">
<value>classpath:alfresco/domain/quartz.properties</value>
</property>
<property name="schedulerName">
<value>DefaultScheduler</value>
</property>
</bean>
# Quartz thread settings 默認的線程優先級為 3
org.quartz.threadPool.threadPriority=3
需要相關的文件配置信息在 file-servers.xml 中
MIME OpenOffice PDF Mail MP3 ...
<!-- load hibernate configuration properties -->
<bean id="hibernateConfigProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:alfresco/domain/hibernate-cfg.properties</value>
</list>
</property>
</bean>
<!-- load hibernate entity cache strategies -->
<bean id="cacheStrategiesPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders">
<value>true</value>
</property>
<property name="locations">
<list>
<value>classpath:alfresco/domain/cache-strategies.properties</value>
</list>
</property>
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" parent="sessionFactoryBase">
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" parent="sessionFactoryBase">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="sessionFactoryBase" abstract="true">
<property name="hibernateProperties" ref="hibernateConfigProperties"/>
不同的Cache策略
<property name="entityCacheStrategies">
<property name="collectionCacheStrategies">
Ownership service support. Use in permissions framework as dynamic authority.
<bean id="ownableService" class="org.alfresco.repo.ownable.impl.OwnableServiceImpl">
script-services-context.xml 腳本引擎 Rhino JavaScript engine.
<!-- index recovery and validation -->
<!--
Recovery types are:
NONE: Ignore
VALIDATE: Checks that the last transaction for each store is represented in the indexes
AUTO: Validates and auto-recovers if validation fails
FULL: Full index rebuild, processing all transactions in order. The server is temporarily suspended.
-->
<bean
id="indexRecoveryComponent"
class="org.alfresco.repo.node.index.FullIndexRecoveryComponent"
parent="indexRecoveryComponentBase">
<property name="recoveryMode">
<value>${index.recovery.mode}</value>
</property>
</bean>
<!-- Bean that attempts to index content that was previously missing -->
<bean
id="missingContentReindexComponent"
class="org.alfresco.repo.node.index.MissingContentReindexComponent"
parent="indexRecoveryComponentBase">
</bean>
<!-- The configuration of the Authority Service Implementation -->
<!-- This implementation supports the identification of users as admin users. -->
<!-- It also supports groups and allows groups and users to be arranged into -->
<!-- hierarchies. -->
<bean id="authorityService" class="org.alfresco.repo.security.authority.AuthorityServiceImpl">
<!-- A list of users with admin rights. -->
<!-- -->
<!-- If the security framework is case sensitive these values should -->
<!-- be case sensitive user names. If the security framework is not -->
<!-- case sensitive these values should be the lower-case user names. -->
<!-- -->
<!-- By default this includes: -->
<!-- admin (the user name of default alfresco admin user) -->
<!-- administrator (the windows default admin user) -->
<!-- -->
<!-- This assumes that user names are not case sensitive. -->
<!-- -->
<property name="adminUsers">
<set>
<value>admin</value>
<value>administrator</value>
</set>
</property>
<!-- Authority DAO that stores group information along with user information, -->
<!-- in the repository. -->
<!-- -->
<!-- This bean uses the userToAuthorityCache configured in cache-context.xml -->
<!-- -->
<bean id="authorityDAO" class="org.alfresco.repo.security.authority.AuthorityDAOImpl">
<!-- This file contains the bean definitions that support authentication -->
<!-- Policy Support -->
如:數據庫、AVM、文件服務器、FTP、NFS、CIFS等等。。。
Repository Bootstrap Sequence.
<!-- ensure that the schema is bootstrapped -->
<bean id="schemaBootstrap" class="org.alfresco.repo.domain.schema.SchemaBootstrap">
<property name="localSessionFactory">
<ref bean="&sessionFactory"></ref> <!-- inject the actual factory, not a session -->
</property>
<!-- Workflow Service Implementation -->
jcr-api-context.xml 實現JCR 170相關的API,即1.0版本的API
Alfresco implementation of a JCR Repository
<!-- ID Issuers. -->
<!-- DAOs for persistent data types -->
<!-- Issuers are not actual entities. More like pseudo entities. -->
<!-- Use substitution values in this config. -->
avm-console.properties 默認配置為本地MySQL的數據庫
# Database specifics.
db.driver=org.gjt.mm.mysql.Driver
db.url=jdbc:mysql://127.0.0.1/avm
db.username=root
db.password=
db.pool.initial=4
db.pool.max=32
# Hibernate properties
hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
hibernate.current_session_context_class=thread
hibernate.connection.isolation=2