SpringBoot高级-自动配置之Enable*注解原理
前言:SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。其底层原理是使用@Import注解导入一些配置类,实现Bean的动态加载。所以,SpringBoot的自动配置,就是依赖于各种Enable开头的注解,而Enable开头的注解,又依赖于@Import注解实现的。
首先,我们来看SpringBoot引导类上的注解@SpringBootApplication,进一步了解引导类中使用的Enable开头的注解。
@SpringBootApplication
public class SpringbootConfigApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootConfigApplication.class, args);
}
}
进入@SpringBootApplication注解中,可以看到,除了三个元注解(元注解这里不解释了,固定用法,所有的注解都包含这三个注解),主要起作用的其它注解,分别解释。
一、@Inherited注解:这个注解的作用可以自己看,讲的很详细,也有示例。链接:https://www.jianshu.com/p/7f54e7250be3 ,主要作用是
①、类继承关系中@Inherited的作用:类继承关系中,子类会继承父类使用的注解中被@Inherited修饰的注解
②、接口继承关系中@Inherited的作用:接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰
③、类实现接口关系中@Inherited的作用:类实现接口时不会继承任何接口中定义的注解
二、@SpringBootConfiguration注解的作用,先进入该注解中,发现该注解就是声明一个配置类,因此,在SpringBoot引导类中,我们也可以定义Bean。
三、@EnableAutoConfiguration注解,进入该注解中,可以发现,其最终是使用了@Import注解,导入一些配置
四、@ComponentScan注解作用:组件扫描。扫描范围:当前引导类所在包及其子包。
综上,@SpringBootApplication注解,依赖的最重要注解就是@EnableAutoConfiguration,及间接依赖的@Import注解。
下面我们做一个示例:验证SpringBoot工程能否直接获取jar包中定义的Bean
一、首先,我们新建一个SpringBoot工程springboot-enable,获取user的Bean
@SpringBootApplication
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
二、再新建一个SpringBoot工程springboot-enable-user,定义User实体类和User配置类
User实体类
/**
* @description:user实体类
* @date: 2020/10/10 10:29
* @author: winson
*/
public class User {
}
User配置类
/**
* @description:User配置类
* @date: 2020/10/10 10:29
* @author: winson
*/
@Configuration
public class UserConfig {
@Bean
public User user() {
return new User();
}
}
三、在springboot-enable工程中,导入springboot-enable-user工程的依赖
<dependency>
<groupId>com.winson</groupId>
<artifactId>springboot-enable-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
四、启动程序,测试user是否注入到了IOC容器中。
结论:SpringBoot工程不能直接获取jar包中定义的Bean
接着上述结果,说明为什么不能直接获取jar包中定义的Bean,这跟引导类@SpringBootApplication注解上的@ComponentScan注解有关系,上述提到了该注解,其扫描范围为引导类所在的包及其子包,而上述测试用的User配置类并不在这个范围内,所以无法获取到。
引导类所在的包为:com.winson.springbootenable
User配置类所在的包为:com.winson.config
下面就上述问题,给出答案,实现SpringBoot工程可以获取jar包中定义的Bean
方法一、使用@ComponentScan注解,将User配置类所在包,加入扫描范围
修改引导类,加入@ComponentScan注解,将User配置类所在包,加入扫描范围
@SpringBootApplication
@ComponentScan("com.winson.config")
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
测试结果:可以发现这时可以获取user的Bean。
方法二、使用@Import注解,将User配置类导入到引导类中
@SpringBootApplication
@Import(UserConfig.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
测试结果:也可以获取user的Bean。
方法三、对@Import注解进行封装
一、新建一个注解类@EnableUser,使用@Import导入User配置类UserConfig
/**
* @description:封装@Import注解
* @date: 2020/10/10 11:20
* @author: winson
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}
二、在引导类中,使用@EnableUser注解
@SpringBootApplication
@EnableUser
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
三、启动程序,测试结果:也可以获取user的Bean。