正文
依赖注入容器
现代Java开发经常利用某种框架管理对象的生命周期及其依赖关系,这个框架一般称为DI(Dependency Injection)容器,DI是指依赖注入,流行的框架有Spring、Guice等,在使用这些框架时,程序员一般不通过new创建对象,而是由容器管理对象的创建,对于依赖的服务,也不需要自己管理,而是使用注解表达依赖关系。这么做的好处有很多,代码更为简单,也更为灵活,比如容器可以根据配置返回一个动态代理,实现AOP,这部分我们后续章节再介绍。
看个简单的例子,Guice定义了Inject注解,可以使用它表达依赖关系,比如像下面这样:
public class OrderService {
@Inject
UserService userService;
@Inject
ProductService productService;
//....
}
Servlet 3.0
Servlet是Java为Web应用提供的技术框架,早期的Servlet只能在web.xml中进行配置,而Servlet 3.0则开始支持注解,可以使用@WebServlet配置一个类为Servlet,比如:
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {...}
Web应用框架
在Web开发中,典型的架构都是MVC(Model-View-Controller),典型的需求是配置哪个方法处理哪个URL的什么HTTP方法,然后将HTTP请求参数映射为Java方法的参数,各种框架如Spring MVC, Jersey等都支持使用注解进行配置,比如,使用Jersey的一个配置示例为:
@Path("/hello")
public class HelloResource {
@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Map
test(
@QueryParam("a")
String a) {
Map
map = new HashMap();
map.put("status", "ok");
return map;
}
}
类HelloResource将处理Jersey配置的根路径下/hello下的所有请求,而test方法将处理/hello/test的GET请求,响应格式为JSON,自动映射HTTP请求参数a到方法参数String a。
神奇的注解
通过以上的例子,我们可以看出,注解似乎有某种神奇的力量,通过简单的声明,就可以达到某种效果。在某些方面,它类似于我们在
62节
介绍的序列化,序列化机制中通过简单的Serializable接口,Java就能自动处理很多复杂的事情。它也类似于我们在并发部分中介绍的
synchronized关键字
,通过它可以自动实现同步访问。
这些都是声明式编程风格,在这种风格中,程序都由三个组件组成:
-
声明的关键字和语法本身
-
系统/框架/库,它们负责解释、执行声明式的语句
-
应用程序,使用声明式风格写程序
在编程的世界里,访问数据库的SQL语言,编写网页样式的CSS,以及后续章节将要介绍的正则表达式、函数式编程都是这种风格,这种风格降低了编程的难度,为应用程序员提供了更为高级的语言,使得程序员可以在更高的抽象层次上思考和解决问题,而不是陷于底层的细节实现。
创建注解
框架和库是怎么实现注解的呢?我们来看注解的创建。
@Override的定义
我们通过一些例子来说明,先看@Override的定义:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public
@interface
Override {
}
定义注解与定义接口有点类似,都用了interface,不过注解的interface前多了@,另外,它还有两个元注解@Target和@Retention,这两个注解专门用于定义注解本身。
@Target
@Target表示注解的目标,@Override的目标是方法(ElementType.METHOD),ElementType是一个枚举,其他可选值有:
-
TYPE:表示类、接口(包括注解),或者枚举声明
-
FIELD:字段,包括枚举常量
-
METHOD:方法
-
PARAMETER:方法中的参数
-
CONSTRUCTOR:构造方法
-
LOCAL_VARIABLE:本地变量
-
ANNOTATION_TYPE:注解类型
-
PACKAGE:包
目标可以有多个,用{}表示,比如@SuppressWarnings的@Target就有多个,定义为:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
如果没有声明@Target,默认为适用于所有类型。