spring-quick-start是SpringFrameWork的一个入门级的例子。通过这个例子,我们还是可以学到一些东西的。
下面这个网址是这个例子的地址:
https://projects.spring.io/spring-framework/
第一步:
这个例子里,首先要下载依赖的类包spring-context,我选择的是用Gradle构建项目,如果你使用的是Maven进行构建的新,可以使用例子中的Maven依赖。
dependencies {
compile 'org.springframework:spring-context:4.3.2.RELEASE'
}
spring-context模块是建立在Beans模块基础上的,并且提供了一些其它功能,例如国际化,事件传递,资源加载,Cache,Validation。而且它还支持很多JavaEE的特性,例如:EJB,JMX,JNDI等。ApplicationContext接口,是这个模块的核心。后面我们就会看到,如果使用ApplicationContext,在启动时把一些类当做Bean加载到Spring框架中,并使用ApplicationContext把那些Bean再读出来,让我们使用。
这个模块依赖了其它Spring的模块或第三方模块,例如:spring-beans,spring-core,spring-apo,commons-logging等等。
第二步:
写3个类:
MessageService.java
:一个接口类,定义了一个接口
MessagePrinter.java
:使用接口的类。它并不是实现接口的类,而是使用接口类。
Application.java
:启动类,并调用了上面的MessagePrinter
来打印东西。
具体代码如下:
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;
@Component
public class MessagePrinter {
final private MessageService service;
@Autowired
public MessagePrinter(MessageService service) {
this.service = service;
}
public void printMessage() {
System.out.println(this.service.getMessage());
}
}
hello/Application.java
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan
public class Application {
@Bean
MessageService mockMessageService() {
return new MessageService() {
public String getMessage() {
return "Hello World!";
}
};
}
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(Application.class);
MessagePrinter printer = context.getBean(MessagePrinter.class);
printer.printMessage();
}
}
下面来讲解上面类中相关的知识点:
(由于MessageService接口没有什么特殊性,省略不讲)
关于MessagePrinter类,首先要看的是两个注解@Component和@Autowired。
@Component:这个注解用在类上面,功能是把使用这个注解的类,自动生成一个Bean,哪个地方需要这个类型,就把它注入进去。
@Autowired:这个注解的功能是,告诉Spring,这个使用这个注解的属性(或方法),是需要从Spring管理的Bean中取得和属性(或方法参数)相同类型的Bean,注入到使用@Autowired的属性(或方法的参数)中去。这个就是我们上面介绍@Component时,所说的“哪个地方需要这个类型”中的所需要的地方。
使用这两个注解,有两个目的:
1,MessagePrinter要变成一个Bean,由Spring进行管理,在需要它的时候使用它(例如注入到属性中,或实例化它)
2,它的构造函数中的参数类型,在Spring管理的Bean中,有相同类型的话,就把那个Bean注入到构造函数的参数中。
关于Application类,这个类要介绍的比较多。
@Bean:这个注释的功能是,把方法的返回值变成一个被Spring管理的Bean。它和@Component很像,不同点就是它是把方法返回值变成Bean,而@Component则是把类变成Bean。
@Configuration:使用@Configuration注解的类标明它是一个bean的原始定义。还有,@Configuration类允许通过调用在相同类中的其他的@Bean方法来定义内部Bean的依赖。也就是有一个类使用@Configuration,这个类中的有两个方法使用了@Bean,其中有一个方法中的属性还依赖了另一个@Bean方法的返回值。
完全的@Configuration VS 简化的 @Bean模式?
当@Bean方法被声明在那些没有使用@Configuration注解注解的类上面,他们就是表面使用了一个简化的模式。例如:在一个@Component中或者甚至在一个普通的POJO类中被声明bean方法将会被当成是简化的模式。和完全的@Configuration不同,简化的@Bean方法不能被简单声明内部bean的依赖。一般来讲一个@Bean方法不应该调用其他的@Bean 方法在以一个简化的模式中。只有在@Configuration 类中使用@Bean方法才可以被建议使用完全的模式。这样可以方法可以防止相同的@Bean方法被多次的调用,从而防止减少了很难追寻的潜在BUG。
例如:把Application类中的MessageService mockMessageService()方法的所有内容移动到一个叫“NoConfigBean”的类中,这个类没有@Configuration注解,只有@Bean注解,再启动Application类的话,就会报错(如下)。但如果加上@Configuration就没有问题。
No qualifying bean of type [hello.MessageService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
你可以使用在任何Spring 的@Component中使用@Bean注解的方法,但是,他们大部分应用在@Configuration 的bean中。
@ComponentScan:可以指定 Spring 框架去扫描指定包及其子包下的存在注解的类。如果不指定默认为当前类所在的包,以及子包。扫描的注解类型为:@Component,@Service,@Controller,@Repository,@Configuration,@Bean。其实这几种注解(除了@Component)内容都是一样的,只不过是注解名字不一样,以一种约定表示被注解的类的目的,用哪个其实最后的结果都是一样的。
有一点需要注意,AnnotationConfigApplicationContext构造函数参数类,在这个类上没有@ComponentScan的话,就不会去扫描那个可以成Bean的注解。原来以为只要其中有一个类上,有这个注解,就会去扫描那些注解。
最后介绍下面的代码:
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
MessagePrinter printer = context.getBean(MessagePrinter.class);
基于Java类定义Bean配置元数据需要通过AnnotationConfigApplicationContext加载配置类及初始化容器,类似于XML配置文件需要使用ClassPathXmlApplicationContext加载配置文件及初始化容器。使用new AnnotationConfigApplicationContext(Application.class)创建应用上下文,构造器参数为使用@Configuration注解的配置类,读取配置类进行实例化相应的Bean。
因为Application类中,有@ComponentScan注解,所以在加载Application的时候,会把其它带上面说的特定注解的类扫描出来,变成Bean管理。
如果没有@ComponentScan注解的话,如何把其它带那个带配置注解的类加载成Bean呢?
有几个方法:
1,在AnnotationConfigApplicationContext构造函数中,指定多个参数,把想要加载的类加载进来。
AnnotationConfigApplicationContext ctx1 = new AnnotationConfigApplicationContext(ApplicationContextConfig.class, ApplicationContextConfig2.class);
2,使用register方法进行注册
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext();
ctx2.register(ApplicationContextConfig.class);
ctx2.register(ApplicationContextConfig2.class);
3,像使用@ComponentScan一样,指定要扫描的包,但是用scan方法来指定。
public void testComponentScan() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("cn.javass.chapter12.confiuration");
ctx.refresh();
}
4,在配置类中,用@Import把其它的配置类加载进来。
@Import({ApplicationContextConfig.class})
5,如果是xml类型的配置文件,可以使用@ImportResource把xml文件加载进来。
@ImportResource({"config1.xml", "config2.xml"})
初始化完容器后,就可以从容器中取得我们想使用的Bean了。就是上面的第二行代码:MessagePrinter printer = context.getBean(MessagePrinter.class);
到此为止,spring-quick-start的讲解基本上完事了,希望对初学者有帮助。
代码地址:(在官方的代码基础上,为了试验做了一些小的修改)
https://github.com/hotdust/spring-quick-start
参考:(参考内容不止下面这些链接,但有一些找不到了,就不列出来了)
http://www.cnblogs.com/zhangminghui/p/4365048.html
http://jinnianshilongnian.iteye.com/blog/1463704