我以爲play的攔截器有點AOP的思想,至關於struts的filter,play的攔截器使用註解方式實現的。java
源碼定義了這麼幾種註解:@before、@after、@catch、@finally 可謂是三百六十度無死角的攔截了。session
標註了@Before的方法會在該類的全部方法以前執行,舉例:less
[java] view plaincopysocket
public class Admin extends Controller { 源碼分析
@Before spa
static void checkAuthentification() { .net
if(session.get("user") == null) login(); 日誌
} code
public static void index() { orm
List<User> users = User.findAll();
render(users);
}
…
}
當請求進入Admin時會先檢查這個類中是否有@before註解,有就優先執行。
固然還有高級點的特性,若是您不想攔截某些方法,您能夠使用unless代表,這樣若是用戶發來login的請求就不會執行@Before了,以下:
[java] view plaincopy
public class Admin extends Controller {
@Before(unless="login")
static void checkAuthentification() {
if(session.get("user") == null) login();
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
一樣,您也能夠使用only屬性,指定須要攔截的請求:
[java] view plaincopy
public class Admin extends Controller {
@Before(only={"login","logout"})
static void doSomething() {
…
}
…
}
@After註解的道理是同樣的,不過是執行了請求方法以後執行
[java] view plaincopy
public class Admin extends Controller {
@After
static void log() {
Logger.info("Action executed ...");
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
下面說說@Catch註解,這個很好用,當程序拋出異常時候能夠被標註了@Catch的方法抓住,咱們能夠在裏面作一些必要的操做,好比rollback等。
[java] view plaincopy
public class Admin extends Controller {
@Catch(IllegalStateException.class)
public static void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public static void index() {
List<User> users = User.findAll();
if (users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}
對了,其中的prioroty屬性能夠設置執行順序的優先級,priority=1是最早執行的。
[java] view plaincopy
public class Admin extends Controller {
@Catch(value = Throwable.class, priority = 1)
public static void logThrowable(Throwable throwable) {
// Custom error logging…
Logger.error("EXCEPTION %s", throwable);
}
@Catch(value = IllegalStateException.class, priority = 2)
public static void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public static void index() {
List<User> users = User.findAll();
if(users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}
@Finally註解的方法和java的finally同樣,無論有沒有執行成功都會進入該方法,咱們能夠在裏面打印日誌:
[java] view plaincopy
public class Admin extends Controller {
@Finally
static void log(Throwable e) {
if( e == null ){
Logger.info("action call was successful");
} else{
Logger.info("action call failed", e);
}
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
上述全部的註解做用域都是類級別的,若是您想對另外的類也起做用,請用@With標籤:
[java] view plaincopy
public class Secure extends Controller {
@Before
static void checkAuthenticated() {
if(!session.containsKey("user")) {
unAuthorized();
}
}
}
@With(Secure.class)
public class Admin extends Controller {
…
}
實現的原理應該是這樣:socket請求發過來的時候,play 的路由會去匹配進入哪一個Controller,而後看這個Controller裏面有哪些系統標籤,而後按規定好的執行順序依次執行,這就是所謂的攔截了。(有時間把源碼分析也一塊兒發出來)
知道原理,咱們就能夠寫本身的攔截器了,好比權限管理:在每一個須要權限的方法上加上自定義的權限註解如:@MyAnatation(priority=1),用戶發起請求——@Before攔截——從登陸token拿到用戶信息——查看該用戶全部權限ID——對比自定義註解的priority——priority在權限ID中則容許訪問,不包含返回無此權限信息。
[java] view plaincopy
@Before(priority = 1)
public static void doAuth(){
Annotation annotation = request.invokedMethod.getAnnotation(MyAnotation.class);
if(annotation !=null){
//鑑權開始
QicFunction function = (QicFunction)annotation;
//todo
}
}
有了這種思想,咱們能夠作任何自定義的攔截行爲,誰也攔不住。
最後,要提醒本身,路漫漫其修遠兮,吾將上下而求索。加油啊!