# 1.SpringBoot中的常用注解标签
在通过SpringBoot框架实现的Java Web项目中,除了我们常用的,SpringMVC当中提供的各种注 解标签之外,
SpringBoot框架本身也为我们提供了一组自己的注解标签,用以辅助我们实现一些配置和功能。 下面我们就来简单了解一下,SpringBoot框架中提供的各种有用的注解标签。
①@Configuration注解标签和@Bean注解标签
说先我们可以回顾一下,落在原生SSM框架整合过程中,如果想要在IOC容器中添加一个自定义 对象,我们所需要完成的工作:
我们需要在Spring框架使用的配置文件的跟标签下,添加如下标签的内容声明:
但是在SpringBoot框架当中,允许我们直接通过创建并返回Java对象的方式,直接向IOC容器中注 入自定义的对象。
这个过程,依赖于@Configuration注解标签和@Bean注解标签。
首先我们准备一个User类:
@Data //记得要导入Lombok相关的依赖
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private Integer age;
}
然后创建一个UserConfiguration类,并为这个类使用@Configuration注解标签,声明这个类是一 个配置类:
@Configuration
public class UserConfiguration {
}
在这个类中创建一个方法,方法的返回值是User类型的,而方法名就是IOC容器中注入对象的对 象名,并对这个方法使用@Bean注解标签:
@Configuration
public class UserConfiguration {
@Bean
public User user() {
/*
下列代码等价于:
方法的返回值数据类型等价于标签中的class属性取值
方法的方法名等价于标签中的id属性取值
*/
User user = new User(1, "张三", 22);
return user;
}
}
此时,SpringBoot框架扫描并向IOC容器注入对象的逻辑流程是:
1.当SpringBoot框架扫描到使用@Configuration注解标签修饰的类型时,将认为这个类是一个配 置类;
2.配置类中使用@Bean注解标签修饰方法的返回值对象,将被自动注入IOC容器中保存;
3.使用@Bean注解标签修饰方法的返回值数据类型等价于标签的class属性取值;
4.默认情况下,使用@Bean注解标签修饰方法的方法名等价于标签的id属性取值,即对 象在IOC容器中的对象名。
通过这种方式,我们可以在不使用XML配置文件的基础上,轻松的向IOC容器中注入自定义的 Java对象。
下面我们来验证一下这种注入方式。
在TestController类中,通过@Autowired注解标签自动注入一个User对象,并在访问test方法的时 候,打印这个User对象:
@Controller //SpringMVC当中的注解标签都还能用
public class TestController {
@Autowired
private User user; //自动注入自定义的User对象
@RequestMapping("/test")
@ResponseBody
public String test() {
System.out.println(user); //打印这个User对象
return "Hello SpringBoot!";
}
}
访问test方法时程序的运行结果:
通过上述实验说明,我们成功的IOC容器中注入了自定义对象。
如果我们需要自定义注入IOC容器中Java对象的对象名称,而不是使用默认的@Bean方法的方法 名作为对象名称时,
我们可以在@Bean注解标签中使用name属性对注入IOC容器中对象的对象名进行自定义:
@Configuration
public class UserConfiguration {
@Bean(name = "myUser") //通过name属性自定义注入对象的对象名称
public User user() {
User user = new User(1, "张三", 22);
return user;
}
}
此时再去通过@Autowired注解标签自动注入对象的时候,就可以使用自定义的对象名了:
@Controller
public class TestController {
@Autowired
private User myUser; //通过自定义的对象名称进行自动注入
@RequestMapping("/test")
@ResponseBody
public String test() {
System.out.println(myUser); //程序依然成功运行
return "Hello SpringBoot!";
}
}
程序运行结果:
②对@SpringBootApplication注解标签的分析
在SpringBoot框架为我们自动创建的启动类当中,使用了@SpringBootApplication注解标签对启动 类进行修饰。
通过源码我们可以发现:@SpringBootApplication注解标签实际上是一个复合注解标签:
package org.springframework.boot.autoconfigure;
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@java.lang.annotation.Inherited
@org.springframework.boot.SpringBootConfiguration
@org.springframework.boot.autoconfigure.EnableAutoConfiguration
@org.springframework.context.annotation.ComponentScan(excludeFilters = {@org.springframework.context.annotation.ComponentScan.Filter(type = org.springframework.context.annotation.FilterType.CUSTOM, classes = {org.springframework.boot.context.TypeExcludeFilter.class}), @org.springframework.context.annotation.ComponentScan.Filter(type = org.springframework.context.annotation.FilterType.CUSTOM, classes = {org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter.class})})
public @interface SpringBootApplication {
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.boot.autoconfigure.EnableAutoConfiguration.class)
java.lang.Class>[] exclude() default {};
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.boot.autoconfigure.EnableAutoConfiguration.class)
java.lang.String[] excludeName() default {};
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.context.annotation.ComponentScan.class, attribute = "basePackages")
java.lang.String[] scanBasePackages() default {};
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.context.annotation.ComponentScan.class, attribute = "basePackageClasses")
java.lang.Class>[] scanBasePackageClasses() default {};
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.context.annotation.ComponentScan.class, attribute = "nameGenerator")
java.lang.Class extends org.springframework.beans.factory.support.BeanNameGenerator> nameGenerator() default org.springframework.beans.factory.support.BeanNameGenerator.class;
@org.springframework.core.annotation.AliasFor(annotation = org.springframework.context.annotation.Configuration.class)
boolean proxyBeanMethods() default true;
}
除去一些对作用目标、生命周期的声明注解之外,@SpringBootApplication注解标签由三个重要的 组成部分构成,分别是:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
下面我们将对这三个重要的构成注解标签进行说明。
1.@SpringBootConfiguration注解标签:
首先我们还是来看@SpringBootConfiguration注解标签的源码:
@Configuration
public @interface SpringBootConfiguration {
... ...
}
我们发现:@SpringBootConfiguration注解标签的本质就是一个@Configuration注解标签,
其目的在于通知SpringBoot框架,声明启动器类本身就是一个配置类,要将通过启动器类创建出 来的所有整合的和自定义的Java对象,加入IOC容器当中。
2.@EnableAutoConfiguration注解标签:
@EnableAutoConfiguration注解标签比较重要,他规定了整个SpringBoot项目中,所有自动注入 对象的注入过程。
也可以说:整个SpringBoot项目的自动装配功能,都是通过@EnableAutoConfiguration注解标签 实现的。
在SpringBoot项目启动的时候,会运行一个名为SpringFactoriesLoader的类中的loadFactories方 法。
SpringFactoriesLoader的类中的loadFactories方法会通过一个for循环读取类中 FACTORIES_RESOURCE_LOCATION变量指定的配置文件路径,
去加载一系列的配置信息。这些配置信息,指定的就是要进行扫描并加入IOC容器中,自动装配的 Java对象所在配置类的类路径。
虽然在SpringFactoriesLoader类当中存在大量的配置类路径信息,但是这些配置类并不是一次性 全部加入IOC容器当中的,
相反的,SpringBoot只会读取那些在pom.xml文件中,通过starter依赖指定的组件的配置类信息。 也就是说:SpringBoot项目中所有自动装配的组件都是可插拔的。
当需要用到这个组件的时候,只要我们在pom.xml文件中声明相应的starter依赖,即可实现自动装 配;在不需要这个组件的时候,只要删除相应的starter依赖即可。
这种做法,有利有弊:
优点:组件可插拔,在需要自动装配某一组件的时候,只要声明相应的starter即可,不需要手动编 写大量的配置文件;
缺点:如果声明了需要自动装配某一组件,那么就必须在SpringBoot的全局配置文件中对其必须 的属性进行声明。
当然,如果我们不希望某个类在项目启动的时候被自动装配,我们也可以使用 @SpringBootApplication注解标签的exclude属性,指定排除自动装配的类型信息:
//指定排除自动装配的类型信息
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class, MultipartAutoConfigu
3.@ComponentScan注解标签:
@ComponentScan注解标签的作用,等价于原生Spring框架配置文件中如下的标签内容:
其作用就是指定在SpringBoot项目启动时,扫描并加载SpringMVC组件(@Controller,@Service、@Repository、@Component)所在包的根路径。
默认情况下,SpringBoot会从启动器类所在的包路径开始向下扫描与其同等级包以及子包中的组 件,这也就解释了为什么我们自定义的TestController类必须放在启动器类的子包当中的原因。
当然,我们可以通过为启动器类手动添加@ComponentScan注解标签,并手动指定扫描包路径的 方式,覆盖这一默认配置:
@ComponentScan(basePackages = "com.qf")
public class TestSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(TestSpringBootApplication.class, args);
}
}