前言
本文將描述 Java 中使用注解(annotation
)的優(yōu)勢及原理(但是不會介紹 Java 注解的使用和自定義,你可以網(wǎng)上搜索相關(guān)資料),以及類似 Java 注解的 Swift Attribute
,同時(shí)還會思考如果 Swift 支持自定義 Attribute 會有什么好處。
Java 使用注解的優(yōu)勢
舉例來說,Java 的 Web 框架 SpringMVC
,這個框架的核心思想之一是使用 Java 的注解來簡化 Web 工程配置。只需很少的代碼就可以構(gòu)造一個 Restful API。如下所示(代碼引用來自 Building a RESTful Web Service 官方 demo):
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
這里簡單的幾句代碼,就完成了一個 /greeting
API 的所有編碼及配置(當(dāng)然,這里忽然了 Model 類)。
SpringMVC
的優(yōu)勢之一是避免了像 Struts2 一樣要配置和維護(hù) XML 文件。所以用戶可以不在過問 XML 文件,使用純 Java 語言來完成所有開發(fā)及配置。
Java 注解原理
Java 編譯器在將源碼編譯成字節(jié)碼的同時(shí),會處理注解符號并附加到字節(jié)碼的結(jié)構(gòu)中。編譯出來的文件大致包含類、類的方法、類的成員變量這三種信息,對于添加了注解的元素,編譯器會同時(shí)在相應(yīng)的元素上添加注解信息。
當(dāng) JVM 開始加載字節(jié)碼文件的時(shí)候,會去讀取類、類的方法、類的成員變量這些信息,當(dāng)發(fā)現(xiàn)讀取的信息中包含注解信息的時(shí)候則去處理這些信息。對待注解信息的邏輯有兩種,一個是類加載完成以后丟棄,一個是類加載完成以后不丟棄。當(dāng)然在編譯階段編譯器也可以處理注解信息,根據(jù)注解信息對用戶輸出編譯警告或者錯誤,所以注解的處理邏輯事實(shí)上有三種。
從這里我們可以發(fā)現(xiàn)注解的實(shí)現(xiàn)實(shí)際上需要兩種支持:
- 編譯器的支持。這樣我們才能將注解信息加入到編譯輸出的文件(對 Java 來說是字節(jié)碼,對 c/c++/objC 來說是 object 文件)
- 類加載支持。根據(jù)編譯輸出的文件結(jié)構(gòu)加載類的時(shí)候,同時(shí)讀取注解信息,根據(jù)注解信息進(jìn)行相應(yīng)的處理
Swift 的注解: Attribute
事實(shí)上很多其他語言也有類似 Java 注解的這種東西,比如 c# 和 Swift 的 Attribute。
Swift 的 Attribute 使用在 Swift 的開發(fā)中其實(shí)也是非常普遍的,比如下面這個 AppDelegate:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}
通過使用 @UIApplicationMain
編譯器就會知道下面的 AppDelegate
這個類就是 app 啟動的時(shí)候系統(tǒng)需要調(diào)用的 app 代理。聯(lián)想一下 ObjC 中我們是這樣使用 AppDelegate
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
所以在相應(yīng)的類定義前面使用 @UIApplicationMain
,我們就不需要自己告訴 iOS 系統(tǒng)該 app 的代理是哪個類。
并且如果你定義的 AppDelegate
沒有實(shí)現(xiàn) UIApplicationDelegate
的話,編譯器在編譯階段就會展示一個編譯錯誤給你,提示你應(yīng)該去實(shí)現(xiàn)這個協(xié)議。
Swift Attribute 的使用及缺點(diǎn)
Swift 語言本身定義了很多 Attribute 給開發(fā)人員使用,你可以查看官方文檔了解使用詳情。
網(wǎng)上有人也整理了一份 Swift 的所有 Attribute 以及說明,swift attributes 符號,當(dāng)然隨著 Swift 的發(fā)展可能會有越來越多的 Attribute 加入,原有的 attribute 也可能有些變化。
目前 Swift Attribute 的缺點(diǎn)是無法支持自定義,也就是說我們無法像 Java 一樣使用注解。官方提供的 Attribute 的效果非常有限。有可能隨著 Swift 的發(fā)展后面會加入對自定義 Attribute 的支持,畢竟 Swift 本身是已經(jīng)支持 Attribute 的。關(guān)于 Swift 支持自定義 Attribute 你可以看 Swift 關(guān)于自定義 Attribute 實(shí)現(xiàn)的討論
如果 Swift 支持自定義 Attribute
讓我們來想一想如果 Swift 可以支持自定義注解的話有什么好的? Medium 上面有人已經(jīng)這樣設(shè)想了,你可以看 Custom Attributes in Swift Language 來了解。
但是對我來說,Swift 自定義 Attribute 的最大一個好處是,會出現(xiàn)類似 SpringMVC
這樣的框架,用于支持 Swift 的后端開發(fā),以及革新移動端開發(fā)方式。
一方面,很多人開始將 Swift 用于后端開發(fā),類似 SpringMVC 這樣的 Swift Web 框架也一定會出現(xiàn)。
另一方面,現(xiàn)在很多移動端開始支持 Router,也就是移動 app 里面頁面的跳轉(zhuǎn)是基于 URL 的,這樣的開源代碼很多比如 JLRoutes,但是基于 URL 的跳轉(zhuǎn)的缺陷是需要配置 URL 跳轉(zhuǎn)邏輯。我們是否可以想象一下,移動端的開發(fā)以后也可以像上面我舉例的 SpringMVC demo 一樣,通過簡單的使用注解,當(dāng)一個 URL 請求來的時(shí)候新的框架能夠自動幫我們解析,并跳轉(zhuǎn)到該界面,省去了配置 URL 和解析 URL?
總結(jié)
Java 注解的使用可以簡化項(xiàng)目的配置,因?yàn)榫幾g器和類加載機(jī)制可以根據(jù)注解來幫助我們完成這一部分配置,使得開發(fā)人員可以專注于語言本身。
另一方法 Swift 的 Attribute 作用則非常有限,但是由于 Swift 本身是支持 Attribute 的,如果未來 Swift 能支持自定義 Attribute 的話,想象空間還是很大的。
引用
- Building a RESTful Web Service
- Swfit 語言官方文檔 - Attribute
- Swift 關(guān)于自定義 Attribute 實(shí)現(xiàn)的討論
- Java 注解機(jī)制及其原理
- Java中的注解是如何工作的?
- 深入理解 Swift 派發(fā)機(jī)制
- swift attributes 符號
- Custom Attributes in Swift Language
- SpringMVC
- JLRoutes
2018年3月3日 更新
最近在了解 Javascript 的原型,以及 ES2016 等標(biāo)準(zhǔn)。發(fā)現(xiàn) Javascript 里面也有類似 Java 的 @ 符號開始的注解,不過 Javascript 里面把它叫做修飾器。原理就是用一個 @ 符號標(biāo)注開始的函數(shù)去修飾另外一個函數(shù)。這種方式很讓我受啟發(fā),本質(zhì)上 Swift 的 extension 就是一種對類、接口等的修飾(或者是 Objective C 的 category)。或許借助 extension 能夠?qū)崿F(xiàn)類似注解的效果?