Spring Boot从一开始就告诉我们,她更喜欢基于Java的配置,即注解的方式。所以她提供了一大堆注解,并让我们习惯使用注解。其最大的特点是无需 XML 配置文件,能自动扫描包路径装载并注入对象,并能做到根据 classpath 下的 jar 包自动配置。这个过程摒弃了spring以往项目中大量繁琐的配置,通过自身默认配置,极大的降低了项目搭建的复杂度。同样在spring boot中,大量注解的使用,使得代码看起来更加简洁,提高开发的效率。这些注解不光包括spring boot自有,也有一些是继承自spring的。
注解的作用
如果说注释是写给人看的,那么注解就是写给程序看的。它更像一个标签,贴在一个类、一个方法或者字段上。它的目的是为当前读取该注解的程序提供判断依据。比如程序只要读到加了@Test的方法,就知道该方法是待测试方法,又比如@Before注解,程序看到这个注解,就知道该方法要放在@Test方法之前执行。
注解就像一个标签,是贴在程序代码上供另一个程序读取的。所以三者关系是
注解就像标签,是程序判断执行的依据。比如,程序读到@Test就知道这个方法是待测试方法,而@Before的方法要在测试方法之前执行
注解需要三要素:定义、使用、读取并执行。
注解分为自定义注解、JDK内置注解和第三方注解(框架)三种。自定义注解一般要我们自己定义、使用、并写程序读取,而JDK内置注解和第三方注解我们只要懂得使用,定义和读取这些我们交给它们,初学者别管太多,先攻城略地。
大多数情况下,三角关系中我们只负责使用注解,无需定义和执行,框架会将注解类和读取注解的程序隐藏起来,除非阅读源码,否则根本看不到。平时见不到定义和读取的过程,光顾着使用注解,这样就很容易让我们忘了注解如何起作用了
格式
public @interface 注解名称{
属性列表;
}
分类
大致分为三类:自定义注解、JDK内置注解、还有第三方框架提供的注解。
自定义注解就是我们自己写的注解。JDK内置注解,比如@Override检验方法重载,@Deprecated标识方法过期等。第三方框架定义的注解比如SpringMVC的@Controller等。
注解的优势
- 注解可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名、类型等信息,如果关系表字段和 PO 属性名、类型都一致,您甚至无需编写任务属性映射信息——因为这些信息都可以通过 Java 反射机制获取。
- 注解和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。
反射
在某种意义上,注解和反射其实是很相似的。所谓反射其实是Java 在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;而对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态的获取信息以及动态调用对象的方法 的功能称为 java 的反射机制。
反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说,Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。Spring Boot 最核心的 3 个注解
@Configuration
Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime
org.springframework.context.annotation.Configuration
这是 Spring 3.0 添加的一个注解,用来代替 applicationContext.xml 配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。我们不妨看看下面几个相关注解也是非常重要的!
@Bean
Indicates that a method produces a bean to be managed by the Spring container.
用来代替 XML 配置文件里面的 <bean ...> 配置。
@ImportResource
如果有些通过类的注册方式配置不了的,可以通过这个注解引入额外的 XML 配置文件,有些老的配置文件无法通过 @Configuration 方式配置的非常管用。
@Import
用来引入额外的一个或者多个 @Configuration 修饰的配置文件类。
@SpringBootConfiguration
这个注解就是 @Configuration 注解的变体,只是用来修饰是 Spring Boot 配置而已,或者可利于 Spring Boot 后续的扩展,源码如下。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@ComponentScan
Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML’s <context:component-scan> element.
org.springframework.context.annotation.ComponentScan
这是 Spring 3.1 添加的一个注解,用来代替配置文件中的 component-scan 配置,开启组件扫描,即自动扫描包路径下的 @Component 注解进行注册 bean 实例到 context 中。
另外,@ComponentScans 是可重复注解,即可以配置多个,用来配置注册不同的子包。
@EnableAutoConfiguration
Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined.
org.springframework.boot.autoconfigure.EnableAutoConfiguration
看全路径就知道,这是自 Spring Boot 诞生时添加的注解,用来提供自动配置,上面的两个都是 spring-context 包下的,不属于 Spring Boot,所以 Spring 3.0 之后的去 XML 配置方式已经为 Spring Boot 埋下了伏笔!
至于说@SpringBootApplication
其实这个 @SpringBootApplication 注解就包含了以上 3 个主要注解,平时没有自定义配置的需求,则使用 @SpringBootApplication 注解完全就可以了!
让我们来看下 @SpringBootApplication 注解的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
观察下面这张图,我们可以更加直观切深刻的感受到SpringBootApplication的源码中的注入依赖关系:)
参考资料:
- Spring Boot 最核心的 3 个注解详解https://link.zhihu.com/?target=http%3A//www.imooc.com/article/254495
- Spring注解https://zhuanlan.zhihu.com/p/60941426
- spring注解学习https://www.jianshu.com/p/7905decddb8e
原文地址:https://blog.51cto.com/yerikyu/2397632