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