使用grails开发已经有一段时间,中间遇到不少问题,由于grails本身提供的文档有点简单,某些功能实现还须参考其源码。在分析过程中逐渐了解其运行构架,稍做介绍。
grails框架是根据约定优于配置这条原则搭建,MVC部分是基于Spring MVC,持久层是基于hibernate。查看打包后的文件目录,找到WEB-INF/web.xml,可以发现核心的几个配置
<filter>
<filter-name>urlMapping</filter-name>
<filter-class>org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>urlMapping</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>grails</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>grails</servlet-name>
<url-pattern>*.dispatch</url-pattern>
</servlet-mapping>
urlMapping filter的作用是根据request uri查找到相应的grails controller的处理路径,然后forward到/grails/controller/action.dispatch,这样就
把请求转到了GrailsDispatcherServlet来处理,调用controller的各种拦截器,处理逻辑,并返回view。
在看看WEB-INF目录下还有两个重要的配置文件,applicationContext.xml和grails.xml
applicationContext.xml,加载grails各种工件(Artefact)和插件(plugin)
<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
<description>Grails application factory bean</description>
<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
<property name="grailsResourceLoader" ref="grailsResourceLoader" />
</bean>
grails.xml:又grails命令生成,包含grails工件和插件
<grails>
<resources>
<resource>ApplicationFilters</resource>
<resource>BootStrap</resource>
<resource>Config</resource>
<resource>DataSource</resource>
<resource>resources</resource>
<resource>UrlMappings</resource>
<resource>MagazineBusinessController</resource>
<resource>BusinessSmsLog</resource>
<resource>MonthBusinessChargeJob</resource>
<resource>SmsChargeService</resource>
<resource>MagazineBusinessService</resource>
<resource>XMLCodec</resource>
<resource>DefaultQuartzConfig</resource>
<resource>QuartzBootStrap</resource>
<resource>JobManagerController</resource>
<resource>JobManagerService</resource>
</resources>
<plugins>
<plugin>QuartzGrailsPlugin</plugin>
<plugin>RemotingGrailsPlugin</plugin>
</plugins>
grails中包含以下几种工件
DomainClass Artefact(Domain模型工件),Controller Artefact(Controller工件),Service Artefact(Service工件),TagLib Artefact(工件),Bootstrap ArtefactHandler(初始化启动工件),
Codec Artefact(Codec工件),UrlMappings Artefact(UrlMapping工件),Filters Artefact(过滤拦截工件)
GrailsApplicationFactoryBean的代码
public void afterPropertiesSet() throws Exception {
if(descriptor != null && descriptor.exists()) {
// Enforce UTF-8 on source code for reloads
CompilerConfiguration config = CompilerConfiguration.DEFAULT;
config.setSourceEncoding("UTF-8");
GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
List classes = new ArrayList();
SAXReader reader = new SAXReader();
InputStream inputStream = null;
try {
inputStream = descriptor.getInputStream();
Document doc = reader.read(inputStream);
List grailsClasses = doc.selectNodes("/grails/resources/resource");
for (Iterator i = grailsClasses.iterator(); i.hasNext();) {
Node node = (Node) i.next();
try {
classes.add(classLoader.loadClass(node.getText()));
} catch (ClassNotFoundException e) {
LOG.warn("Class with name ["+node.getText()+"] was not found, and hence not loaded. Possible empty class or script definition?");
}
}
} finally {
if(inputStream!=null)
inputStream.close();
}
Class[] loadedClasses = (Class[])classes.toArray(new Class[classes.size()]);
this.grailsApplication = new DefaultGrailsApplication(loadedClasses, classLoader);
}
else {
Assert.notNull(resourceLoader, "Property [resourceLoader] must be set!");
this.grailsApplication = new DefaultGrailsApplication(this.resourceLoader);
}
ApplicationHolder.setApplication(this.grailsApplication);
}
GrailsApplicationFactoryBean已经把grails.xml中所有的grails工件类加载了进来,保存在DefaultGrailsApplication中
DefaultGrailsApplication的代码
public DefaultGrailsApplication(final Class[] classes, GroovyClassLoader classLoader) {
...
this.allClasses = classes;
this.cl = classLoader;
this.applicationMeta = loadMetadata();//读取WEB-INF/classes下application.properties配置
}
private void initArtefactHandlers() {
registerArtefactHandler(new DomainClassArtefactHandler());
registerArtefactHandler(new ControllerArtefactHandler());
registerArtefactHandler(new ServiceArtefactHandler());
registerArtefactHandler(new TagLibArtefactHandler());
registerArtefactHandler(new BootstrapArtefactHandler());
registerArtefactHandler(new CodecArtefactHandler());
registerArtefactHandler(new UrlMappingsArtefactHandler());
// Cache the list as an array
this.artefactHandlers = ((ArtefactHandler[]) this.artefactHandlersByName.values().toArray(
new ArtefactHandler[artefactHandlersByName.size()]));
}
public boolean isArtefact(Class theClazz) {
String className = theClazz.getName();
for (Iterator i = allArtefactClasses.iterator(); i.hasNext();) {
Class artefactClass = (Class) i.next();
if (className.equals(artefactClass.getName())) {
return true;
}
}
return false;
}
就此分析GrailsApplication接口代表是应用中所有的工件,而ArtefactHandler是工件接口
public interface GrailsApplication extends ApplicationContextAware {
public Class[] getAllClasses();
public Class[] getAllArtefacts();
public boolean isArtefact(Class theClazz);
}
public interface ArtefactHandler {
boolean isArtefact(Class aClass);
GrailsClass newArtefactClass(Class artefactClass);
}
待续,后面准备就UrlMapping机制看看grails是如何处理工件再做分析