16-SpringBoot自动配置-Enable注解原理

Enable注解原理

@Enable* 注解

SpringBoot提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用 @Import 注解导入一些配置类,实现 Bean 的动态加载。

思考

SpringBoot工程是否可以直接获取在其他工程定义的 bean 呢?

下面我们创建两个工程来演示一下:

  • 一个工程演示如何获取其他工程定义的bean
  • 一个工程编写 bean

案例

1.创建 springboot-enable 工程:用来获取其他工程的 bean


16-SpringBoot自动配置-Enable注解原理_spring boot

2.创建 springboot-enable-other 工程:用来定义 bean


16-SpringBoot自动配置-Enable注解原理_spring boot_02

3.【springboot-enable-other】定义 bean

编写 User 类 以及 返回 User bean 对象的配置类


16-SpringBoot自动配置-Enable注解原理_java_03

User:

package com.lijw.springbootenableother.domain;

public class User {
}

UserConfig:

package com.lijw.springbootenableother.config;

import com.lijw.springbootenableother.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

@Bean
public User user(){
return new User();
}
}

4.【springboot-enable】引入 【 springboot-enable-other】的工程依赖


16-SpringBoot自动配置-Enable注解原理_spring boot_04

<!--  引入 springboot-enable-other  -->
<dependency>
<groupId>com.lijw</groupId>
<artifactId>springboot-enable-other</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

5.【springboot-enable】获取 【 springboot-enable-other】工程的 User类 bean

16-SpringBoot自动配置-Enable注解原理_java_05

代码如下:

package com.lijw.springbootenable;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SpringbootEnableApplication {

public static void main(String[] args) {
// 获取IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
// 其他工程
Object user = context.getBean("user");
System.out.println(user);
}

}

从结果来看获取不到 user 的 bean 对象,那么为什么会获取不到呢?

让我们进入一下@SpringBootApplication的注解,如下:


16-SpringBoot自动配置-Enable注解原理_spring_0616-SpringBoot自动配置-Enable注解原理_spring_07

SpringBoot的应用注解默认只会扫描 应用引导类下的包:


16-SpringBoot自动配置-Enable注解原理_spring_08

如果希望扫描其他工程的 bean,那么可以增加扫描包的范围。

6.【springboot-enable】增加扫描其他工程的包

16-SpringBoot自动配置-Enable注解原理_spring boot_09

@SpringBootApplication
@ComponentScan("com.lijw.springbootenableother.config")
public class SpringbootEnableApplication {

虽然按照上面的方法,我们已经可以扫描其他工程的类了,但是如果类特别多,这种写法是很不方便的。

我们可以修改一下,采用 @Import 配置类的方式

7.【springboot-enable】使用 @Import 直接导入其他工程的配置类,获取 bean

16-SpringBoot自动配置-Enable注解原理_spring_10

@Import(UserConfig.class)

这样我们也可以获取到配置类中的 bean,虽然比之前扫描包要好,但是如果每次需要这样导入配置类,还是很不方便的。

有没有办法让第三方工程自己定义好注解,我使用的时候直接添加个注解就可以了呢?

这时候我们可以写一个 @Enable* 注解。

8.【springboot-enable-other】定义 @EnableUser 注解类


16-SpringBoot自动配置-Enable注解原理_mybatis_11

package com.lijw.springbootenableother.config;


import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}

我们在 @EnableUser 中添加 @Import 配置类的内容,这样就不用让引入工程去写了。

9.【springboot-enable】使用 @EnableUser 导入其他工程的配置类,获取 bean

16-SpringBoot自动配置-Enable注解原理_java_12

小结

SpringBoot应用默认扫描不到其他工程的 bean

原因:@ComponentScan 扫描范围:当前引导类所在包及其子包

三种解决方案:

1.使用@ComponentScan扫描第三方工程的包

2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器

3.可以对Import注解进行封装。

重点:Enable注解底层原理是使用@Import注解实现Bean的动态加载