SpringBoot⾃动配置之Enable注解原理
⽂章⽬录
前⾔
在 SpringBoot 中提供了很多 Enable 开头的注解,这些注解都是⽤于动态启⽤某些功能的。⽽其底层原理是使⽤ @Import 注解导⼊⼀些配置类,实现 Bean 的动态加载。
@Enable* 注解
思考
SpringBoot ⼯程是否可以直接获取 jar 包中定义的 Bean?
答案是否定的,SpringBoot ⽆法直接引⽤别⼈ jar 包⾥的 Bean。
那么问题就来了:为什么我们之前在⼯程中引⼊⼀个 Redis 的起步依赖就可以直接获取到 RedisTemplate 呢?
演⽰
我们接下来演⽰⼀下 SpringBoot 不能获取第三⽅ jar 包⾥的 Bean 这个特点。
因为要模拟演⽰第三⽅的,我们需要创建两个模块⼯程:
springboot-enable、springboot-enable-other。
由于是演⽰,那么就简单写⼀些代码实现效果就可以。
springboot-enable-other
在 springboot-enable-other ⼯程中写⼀个 Bean:
User 类
package;
public class UserConfig {
}
UserConfig 配置类
package;
import User;
import Bean;
import Configuration;
/** 表⽰配置类 */
@Configuration
public class UserConfig {
/** 注⼊ */
@Bean
public User user(){
return new User();
}
}
springboot-enable
在 springboot-enable ⼯程中依赖 springboot-enable-other ⼯程。
<dependency>
<groupId>com.xh</groupId>
<artifactId>springboot-enable-other</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改启动类中添加获取 User 的代码:
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
// 获取 Bean
Object user = Bean("user");
System.out.println(user);
}
运⾏项⽬,提⽰没有获取到为 user 的 Bean:
通过演⽰我们可以看到 SpringBoot 不能直接获取我们在其他⼯程中定义的 Bean。
原因:在启动类中 @SpringBootApplication 注解中有⼀个 @ComponentScan 注解,这个注解扫描的范围是当前引导类所在包及其⼦包。
我们项⽬的引导类包路径为:om.xh.springbootenable
⽽ UserConfig 所在的包路径为:fig
两者并没有关联关系,那么我们如果想解决这个问题其实是有很多种⽅案的。
⽅案
1. 使⽤ @ComponentScan
我们可以在引导类上使⽤ @ComponentScan 注解扫描配置类所在的包
@SpringBootApplication
@ComponentScan("fig")
public class SpringbootEnableApplication {
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
// 获取 Bean
Object user = Bean("user");
System.out.println(user);
}
}
启动项⽬,输出成功获取到的 user
这样的⽅案虽然可以解决这个问题,但是看起来还是不太⾏,如果我们后期需要⽤到第三⽅的⼀些功能,还需要把第三⽅的包扫描⼀下,如果获取的特别多的话,那么写⼀排实在是太 low 了!⽽且也很难能记住那么多的包路径,所以这种⽅案是不推荐的。
2.使⽤ @Import 注解
被 @Import 注解所导⼊的类,都会被 Spring 创建,并放⼊ IOC 容器中。
如图可以看到 @Import 注解的 value 值是⼀个数组,可以传多个值。
修改引导类
@SpringBootApplication
//@ComponentScan("fig")
@Import(UserConfig.class)
public class SpringbootEnableApplication {
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
// 获取 Bean
Object user = Bean("user");
System.out.println(user);
}
}
启动项⽬,输出成功获取到的 user
这种⽅案⽐⽅案⼀稍微好⼀些,但同样会⾯临同样的问题,我们需要记住很多类的名字,所以仍然不是很⽅便。
3.对 @Import 注解进⾏封装
在 springboot-enable-other ⼯程中编写注解 @EnableUser,在注解中使⽤ @Import 注解导⼊ UserConfig,并且添加 @Import 的元注解
package;
import Import;
import*;
@Import(UserConfig.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface EnableUser {
}
修改 springboot-enable ⼯程的引导类,现在可以使⽤我们⾃定义的注解。
@SpringBootApplication
//@ComponentScan("fig")
//@Import(UserConfig.class)
@EnableUser
public class SpringbootEnableApplication {
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
// 获取 Bean
Object user = Bean("user");
System.out.println(user);
}
}
启动项⽬,输出成功获取到的 user
这种⾃定义注解的⽅式和⽅案⼆是⼀个原理,只不过是在使⽤上简化了⼀下。
⼩结
SpringBoot 底层是使⽤ @Import 注解导⼊⼀些配置类,实现 Bean 的动态加载。
例如 @SpringBootApplication 其中的 @EnableAutoConfiguration 就使⽤了 @Import 来实现导⼊其他的类。
@Import 注解
spring ioc注解@Enable* 底层依赖于 @Import 注解导⼊⼀些类,使⽤ @Import 导⼊的类会被 Spring 加载到 IOC 容器中。@Import 4 种⽤法
@Import 提供了 4 种⽤法:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论