04SpringBoot 启动类配置

04SpringBoot 启动类配置,第1张

上一章中我们提到,springboot通过父项目依赖和starter的场景启动器来管理和启动相关组件,以 spring-boot-starter-web 场景管理器为例,它能够为提供 Web 开发场景所需要的几乎所有依赖,因此在使用 Spring Boot 开发 Web 项目时,只需要引入该 Starter 即可,而不需要额外导入 Web 服务器和其他的 Web 依赖。

但我们在启动springboot项目时候,springboot是如何按需加载所需要的自动配置配置项?引入哪些场景,这些场景的自动配置才会开始呢?下面以springboot启动类注解来说明。

SpringBoot启动类配置
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        String[] names =run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

默认情况下,Spring Boot 项目会创建一个名为 ***Application 的主程序启动类 ,该类中使用了一个组合注解 @SpringBootApplication,用来开启 Spring Boot 的自动配置,另外该启动类中包含一个 main() 方法,用来启动该项目。

其中 @SpringBootApplication可以使用下面三个注解替换,但要指定xxxApplication所在的包路径

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example.demo")//注意,这里要指定DemoApplication所在的包
public class DemoApplication {

    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        String[] names =run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

1. @SpringBootApplication

@SpringBootApplication 注解表明该类是springBoot的主配置类,应运行该类的主方法启动SpringBoot应用,改注解是有以下多个注解组成。

@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 {...}

2. @ComponentScan(了解)

@CmponentScan标注用于指定要扫描的包,将哪些包下面的带有实例化注解的类进行扫描,生成组件,交给SpringIOC容器管理。参数是包路径。

如果用在主启动类中,包路径必须是主启动类所在的包,否则扫描不到主启动类,无法启动报错。

3. @SpringBootConfiguration

@Configuration标注在一个类上,说明该类SpringBootConfiguration是配置类,是springBoot的一个配置类;即 @SpringBootConfiguration标注在一个类似上,这个类也是是springBoot的一个配置类;在主程序 DemoApplication 上适应,说明主程序DemoApplication也可以作为配置类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {....}

4. @Configuration

@Configuration底层

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

    boolean proxyBeanMethods() default true;
}

@Configuration是配置类注解,是spring的底层注解;从@Component可以看出配置类也是一个组件;这个注解@Configuration用在类上,表示告诉spring这个类是配置类===配置文件

@Configuration // 告诉spring这是一个配置类 ==  配置文件
public class DemoConfig {
    @Bean // 给容器中添加组件,以方法名为组件id,返回的值就是组件
    public User user(){
        return new User();
    }
}

上述代码等价与在xml中配置bean标签

@Configuration修饰的类,默认带有参数proxyBeanMethods,参数proxyBeanMethods默认值是true。

proxyBeanMethods=true:如果为true值,springboot总会检查这个组件在容器中是否存在,如果存在则不会新创建对象。配置类对象是被cglib代理类增强的代理对象。调用配置类中的注册方法都是得到的都是同一个bean对象。即@Configuration默认创建的bean对象是单例的。

@Configuration //默认使用属性@Configuration(proxyBeanMethods=true)
public class DemoConfig {
    @Bean // 给容器中添加组件,以方法名为组件id,返回的值就是组件
    public User user(){
        return new User();
    }
}

测试类


@SpringBootApplication
public class DemoApplication {
 
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
 
        //配置类的测试使用
        //从容器中获取组件
        User user = run.getBean("user", User.class);
        //从容器中获取配置类组件,配置类组件是一个代理对象
        DemoConfig demoConfig = run.getBean(DemoConfig.class);
        User user0 =  demoConfig.user();
        User user1 =  demoConfig.user();
        System.out.println(user0==user1);
    }
}

proxyBeanMethods=false:如果为fasle值,则springboot不会检查这个组件在容器中是否存在,配置类对象不是被cglib代理类增强的代理对象,调用配置类中的注册方法都是得到的是不同的bean对象。

 @Configuration (proxyBeanMethods=false)
public class DemoConfig {
    @Bean // 给容器中添加组件,以方法名为组件id,返回的值就是组件
    public User user(){
        return new User();
    }
}

测试类


@SpringBootApplication
public class DemoApplication {
 
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
 
        //配置类的测试使用
        //从容器中获取组件
        User user = run.getBean("user", User.class);
        //从容器中获取配置类组件,配置类组件是一个代理对象
        DemoConfig demoConfig = run.getBean(DemoConfig.class);
        User user0 =  demoConfig.user();
        User user1 =  demoConfig.user();
        System.out.println(user0==user1);
    }
}

5. @EnableAutoConfiguration(重头戏)

@EnableAutoConfiguration:开启自动配置功能;

以前需要配置的东西,现在springBoot帮我们自动配置,通过这个注解开启自动配置;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class[] exclude() default {};

    String[] excludeName() default {};
}

@AutoConfigurationPackage

  • 自动配置包,将主配置类(@SpringBootApplication标注的类)的所在包下的所有子包内的所有组件全部加入到spring容器中;

@Import(AutoConfigurationPackages.Registrar.class)

  • spring底层注解@import,给容器导入一个组件Registrar;再由组件Registrar 导入一系列其他的组件
  • 组件Registrar 导入指定路径下的包

 

@Import({AutoConfigurationImportSelector.class})

  • spring底层注解@import,给容器导入一个组件;导入的组件由AutoConfigurationImportSelector.class提供;AutoConfigurationImportSelector批量导入组件,它决定导入哪些组件,过程如下图源码:

通过源码发现:

  • 通过getAutoConfigurationEntry(annotationMetadata)方法导入一些组件。
  • 通过List configurations = getCandidateConfigurations(annotationMetadata, attributes)方法获取所有要导入的组件。
  • 通过List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader)
  • 通过Map> loadSpringFactories(ClassLoader classLoader)
  • 从META-INF/spring.factories位置加载一个文件,就是默认扫描当前系统所有META-INF/spring.factories位置的文件。
  • 重点是spring-boot-autoconfigure-2.6.7.jar包下的META-INF/spring.factories文件,里面配置好了要自动加载的组件有哪些。如下图:

 

5. @Import导入某个组件

例如导入自动配置选择器组件:@Import({AutoConfigurationImportSelector.class}) ,也可以导入多个组件,组件之间用逗号隔开。导入组件在IOC容器中的名字默认是类的全限定名。

@SpringBootApplication
@Import(User.class)
public class DemoApplication {
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        String[] names = run.getBeanNamesForType(User.class);
        for (String name : names) {
            System.out.println(name);
        }
    }
}

6. @ImportResource导入spring的配置类

@ImportResource用来导入spring的配置文件,例如@ImportResource(“classpath:springbean.xml”)

步骤1:service类

public class MyServicve {
}

步骤2:创建配置文件

在resources目录下新建一个名为beans.xml的XML自定义配置文件,在该配置文件中通过配置向Spring容器中添加MyConfigServicve类对象。




    

步骤3:在启动类上引入XML文件

@SpringBootApplication
@ImportResource("classpath:beans.xml")
public class DemoApplication {
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = 
                     SpringApplication.run(DemoApplication.class, args);
        //2、查看容器中的组件
        MyServicve  servicve = run.getBean(MyServicve.class);
        System.out.println(servicve);
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/922546.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存