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。

小结:SpringBoot自动配置依赖于各种@Enable开头的注解,@Enable开头的注解,底层还是通过@Import注解实现的,所以自动配置的最核心就是使用了@Import注解

posted @ 2020-10-10 11:33  温森  阅读(1595)  评论(0编辑  收藏  举报