顾建辉(C/C++)

最近在工作用到了Spring框架,由于以前没有接触过Spring,就从Spring的官方文档开始学起。在“Quick Start”介绍了一个使用Spring做依赖性注入(dependency injection)的例子,该例子使用Maven或GRADlE进行管理的。作者以前没有接触过这两个项目管理工具,由于时间紧迫,就直接使用了Eclipse编译了这个例子。在Eclipse下的文件结构如下:

(由于没有使用项目管理工具,刚开始只加入了spring-context.jar和spring-core.jar,又根据异常信息导入了commouns-logging.jar、spring-expression.jar和spring-beans.jar。这就是不是项目管理工具的麻烦所在。)

hello/MessageService.java的代码如下:

package hello;public interface MessageService {String getMessage();}hello/MessagePrinter.java的代码如下:package hello;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Componentpublic class MessagePrinter {final private MessageService service;@Autowiredpublic MessagePrinter(MessageService service) {this.service = service;}public void printMessage() {System.out.println(this.service.getMessage());}}hello/App.java的代码如下:package hello;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.*;@Configuration@ComponentScanpublic class App {@BeanMessageService mockMessageService() {return new MessageService() {public String getMessage() {return "Hello World!";}};} public static void main(String[] args) {ApplicationContext context =new AnnotationConfigApplicationContext(App.class);MessagePrinter printer = context.getBean(MessagePrinter.class);printer.printMessage(); }}

编译运行该项目,,会有以下输出:

“Quick Start”最后总结说这个充分体现了依赖性注入(dependency injection)的概念,至于如何体现的作者尝试做一下解析,权当对Spring Framework的一个初步认识。

项目的入口是App.java的main函数,在这个函数中首先声明了一个ApplicationContext对象context,并向下转型为AnnotationConfigApplicationContext对象。ApplicationContext是对一个应用(Application)提供配置的核心接口,AnnotationConfigApplicationContext是它的一个实现,可用来处理用@Configuration,@Component和JSR-330标注的类。由于App.java使用@Configuration进行了标注,故App.class可以作为AnnotationConfigApplicationContext构造器的的参数。

MessagePrinter printer = context.getBean(MessagePrinter.class);这句代码通过context的getBean(Class<T>)方法得到了MessagePrinter的一个实例。为什么呢得到MessagePrinter类的一个实例呢?看getBean(Class<T>)的API解释:

Return the bean instance that uniquely matches the given object type, if any.

(如果给定的对象唯一匹配,就返回一个bean实例。)

printer.printMessage();调用MessagePrinter的printMessage()方法,该方法如下实现: public void printMessage() {System.out.println(this.service.getMessage());}其实是调用了接口MessageService的getMessage()方法,由于App.java中的mockMessageService()方法中的匿名内部类实现了MessageService接口,并在getMessage()方法中返回了“hello,world!”字符串,顾能在结果中输出"hello,world!"。

令人迷惑的是在mockMessageService()方法并没有被显式调用,为何其匿名内部类能被实例化并输出信息呢?原因就在于程序中使用的以下Spring标注。

@Configuration 用于标注一个类,表示bean定义的源文件(source);

@Bean 用于标注一个方法,表示一个方法实例化、配置或初始化一个新的对象(Object),这个对象被Spring的控制反转(IoC)容器管理,相当于Spring <bean />XML配置文件中<bean />元素。(详见)

@ComponentScan 用于标注一个类,表示扫描指定包中的@Component标注的类,并将这些类注册为Spring IoC容器的bean,亦相当于一个<bean />元素;

@Autowired 用于标注setter方法,构造器,包含多个参数的方法,集合等等,用于自动绑定;

@Component 用于标注一个类

由于MessagePrinter中有如下构造器:

@Autowiredpublic MessagePrinter(MessageService service) {this.service = service;}从这个构造器中可以到MessagePrinter依赖MessgeServie,并用@Autowired标注。这就表示在通过contexnt.getBean(MessagePrinter.class)得到MessagePrinter的一个实例时,会将对MessageService的依赖自动绑定到MessageService类,将查找所有能作为<bean />元素的类(@Component @Configuration标注)或方法(@Bean标注),而在App.java中有如下方法: @BeanMessageService mockMessageService() {return new MessageService() {public String getMessage() {return "Hello World!";}};}查找到这个方法后会将这个MessageService实现注入到MessagePrinter实例中,从而实现“hello,world!”的输出。

以上就是作者对Spring Framework文档“Quick Start”例子的解析,有不当之处=请多多指教。

旅行,重复一个承诺和梦想,听他第二十八次提起童年往事,

顾建辉(C/C++)

相关文章:

你感兴趣的文章:

标签云: