22.2 框架和库的注解

22.2 框架和库的注解

各种框架和库定义了大量的注解,程序员使用这些注解配置框架和库,与它们进行交互,我们先来看一些例子,包括Jackson、依赖注入容器、Servlet 3.0、Web应用框架等,最后我们总结下使用注解的思维逻辑。

1. Jackson

Jackson是一个通用的序列化库,程序员可以使用它提供的注解对序列化进行定制,比如:

  • 使用@JsonIgnore@JsonIgnoreProperties配置忽略字段。
  • 使用@JsonManagedReference@JsonBackReference配置互相引用关系。
  • 使用@JsonProperty@JsonFormat配置字段的名称和格式等。

在Java提供注解功能之前,同样的配置功能也是可以实现的,一般通过配置文件实现,但是配置项和要配置的程序元素不在一个地方,难以管理和维护,使用注解就简单多了,代码和配置放在一起,一目了然,易于理解和维护。

2.依赖注入容器

现代Java开发经常利用某种框架管理对象的生命周期及其依赖关系,这个框架一般称为DI(Dependency Injection)容器。DI是指依赖注入,流行的框架有Spring、Guice等。在使用这些框架时,程序员一般不通过new创建对象,而是由容器管理对象的创建,对于依赖的服务,也不需要自己管理,而是使用注解表达依赖关系。这么做的好处有很多,代码更为简单,也更为灵活,比如容器可以根据配置返回一个动态代理,实现AOP,这部分我们在下一章再介绍。

看个简单的例子,Guice定义了Inject注解,可以使用它表达依赖关系,比如像下面这样:

1
2
3
4
5
6
7
public class OrderService {
@Inject
UserService userService;
@Inject
ProductService productService;
//…
}

3. Servlet 3.0

Servlet是Java为Web应用提供的技术框架,早期的Servlet只能在web.xml中进行配置,而Servlet 3.0则开始支持注解,可以使用@WebServlet配置一个类为Servlet,比如:

1
2
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {…}

4. Web应用框架

在Web开发中,典型的架构都是MVC(Model-View-Controller),典型的需求是配置哪个方法处理哪个URL的什么HTTP方法,然后将HTTP请求参数映射为Java方法的参数。各种框架如Spring MVC、Jersey等都支持使用注解进行配置,比如,使用Jersey的一个配置示例为:

1
2
3
4
5
6
7
8
9
10
11
12
@Path("/hello")
public class HelloResource {
@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> test(
@QueryParam("a") String a) {
Map<String, Object> map = new HashMap<>();
map.put("status", "ok");
return map;
}
}

类HelloResource将处理Jersey配置的根路径下/hello下的所有请求,而test方法将处理/hello/test的GET请求,响应格式为JSON,自动映射HTTP请求参数a到方法参数String a。

5.神奇的注解

通过以上的例子,我们可以看出,注解似乎有某种神奇的力量,通过简单的声明,就可以达到某种效果。在某些方面,它类似于我们之前介绍的序列化,序列化机制中通过简单的Serializable接口,Java就能自动处理很多复杂的事情。它也类似于我们在并发部分中介绍的synchronized关键字,通过它可以自动实现同步访问。

这些都是声明式编程风格,在这种风格中,程序都由三个组件组成:

  • 声明的关键字和语法本身。
  • 系统/框架/库,它们负责解释、执行声明式的语句。
  • 应用程序,使用声明式风格写程序。

在编程的世界里,访问数据库的SQL语言、编写网页样式的CSS,以及后续章节将要介绍的正则表达式、函数式编程都是这种风格,这种风格降低了编程的难度,为应用程序员提供了更为高级的语言,使得程序员可以在更高的抽象层次上思考和解决问题,而不是陷于底层的细节实现