在处理了我们应用的代码之后,就会再次进入Play框架的范围,我们就接着说下一个请求的下半生。 在Controller中定义一系列的render方法:
可以对应到play.mvc.results包中各种Render开头的类:
重点在RenderTemplate中。
public class Controller implements ControllerSupport, LocalVariablesSupport {
...
protected static String template() {
final Request theRequest = Request.current();
final String format = theRequest.format;
String templateName = theRequest.action.replace(".", "/") + "." + (format == null ? "html" : format);
if (templateName.startsWith("@")) {
templateName = templateName.substring(1);
if (!templateName.contains(".")) {
templateName = theRequest.controller + "." + templateName;
}
templateName = templateName.replace(".", "/") + "." + (format == null ? "html" : format);
}
return null == templateNameResolver ? templateName : templateNameResolver.resolveTemplateName(templateName);
}
...
}
当我们用render方法,没有写模版名称时,在play.mvc。Controller:template()方法中play会依据request中action名称等参数构建template路径。
public class TemplateLoader {
...
public static BaseTemplate load(String key, String source) {
if (!templates.containsKey(key) || templates.get(key).compiledTemplate == null) {
BaseTemplate template = new GroovyTemplate(key, source);
if (template.loadFromCache()) {
templates.put(key, template);
} else {
templates.put(key, new GroovyTemplateCompiler().compile(template));
}
} else {
BaseTemplate template = new GroovyTemplate(key, source);
if (Play.mode == Play.Mode.DEV) {
templates.put(key, new GroovyTemplateCompiler().compile(template));
}
}
if (templates.get(key) == null) {
throw new TemplateNotFoundException(key);
}
return templates.get(key);
}
...
}
我们可以看到,最后会用GroovyTemplate封装读到的template文件。然后当作异常抛出。ActionInvoker.invoke捕捉到。
public class ActionInvoker {
...
public static void invoke(Http.Request request, Http.Response response) {
Monitor monitor = null;
try {
....
try {
...
if (actionResult == null) {
ControllerInstrumentation.initActionCall();
try {
inferResult(invokeControllerMethod(actionMethod));
} catch(Result result) {
actionResult = result;
// Cache it if needed
if (cacheKey != null) {
play.cache.Cache.set(cacheKey, actionResult, actionMethod.getAnnotation(CacheFor.class).value());
}
} catch (InvocationTargetException ex) {
...
}
}
// @After
handleAfters(request);
monitor.stop();
monitor = null;
// OK, re-throw the original action result
if (actionResult != null) {
throw actionResult;
}
throw new NoResult();
} catch (...) {
...
}
} catch (Result result) {
Play.pluginCollection.onActionInvocationResult(result);
Scope.Session.current().save();
Scope.Flash.current().save();
result.apply(request, response);
Play.pluginCollection.afterActionInvocation();
// @Finally
handleFinallies(request, null);
} catch (...) {
...
} finally {
...
}
}
...
}
其中 result.apply(request, response);
是第二张图中所显示的所有结果类都覆写的方法,如play.mvc.results中,直接将结果写到response中。
public class RenderTemplate extends Result {
...
public void apply(Request request, Response response) {
try {
final String contentType = MimeTypes.getContentType(name, "text/plain");
response.out.write(content.getBytes(getEncoding()));
setContentTypeIfNotSet(response, contentType);
} catch (Exception e) {
throw new UnexpectedException(e);
}
}
...
}
play之后会处理After注解的方法。将发出调用结束的事件onActionInvocationResult,ValidationPlugin会响应。最后是处理Finally注解。 回到JPA中来,Play将处理事务。并判定是否要回滚事务。
public class JPA {
...
public static T withTransaction(String dbName, boolean readOnly, F.Function0 block) throws Throwable {
if (isEnabled()) {
boolean closeEm = true;
// For each existing persisence unit
try {
...
T result = block.apply();
boolean rollbackAll = false;
// Get back our entity managers
// Because people might have mess up with the current entity managers
for (JPAContext jpaContext : get().values()) {
EntityManager m = jpaContext.entityManager;
EntityTransaction localTx = m.getTransaction();
// The resource transaction must be in progress in order to determine if it has been marked for rollback
if (localTx.isActive() && localTx.getRollbackOnly()) {
rollbackAll = true;
}
}
for (JPAContext jpaContext : get().values()) {
EntityManager m = jpaContext.entityManager;
boolean ro = jpaContext.readonly;
EntityTransaction localTx = m.getTransaction();
// transaction must be active to make some rollback or commit
if (localTx.isActive()) {
if (rollbackAll || ro) {
localTx.rollback();
} else {
localTx.commit();
}
}
}
return result;
} catch (...) {
....
} finally {
...
}
} else {
return block.apply();
}
}
...
}
再回到Invoker中,after中发出afterInvocation事件,onSuccess以及onInvocationSuccess事件。
public static abstract class Invocation implements Runnable {
...
public void run() {
if (waitInQueue != null) {
waitInQueue.stop();
}
try {
preInit();
if (init()) {
before();
boolean withinFilterFctFound = this.withinFilter(new play.libs.F.Function0() {
public Void apply() throws Throwable {
execute();
return null;
}
});
if(!withinFilterFctFound){
execute();
}
after();
onSuccess();
}
} catch (Suspend e) {
suspend(e);
after();
} catch (Throwable e) {
onException(e);
} finally {
_finally();
}
}
...
}
play框架大体就处理结束。一个访问的旅程结束了。