原 SpringBoot 2.0 系列00

SpringBoot 2.0 系列005 --启动实战之SpringApplication应用

注意是只使用了@EnableAutoConfiguration,默认是只扫描这一个我们自定义的类到bean中。不含子包和本包。下一篇我们分析原因。

package hello;

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

@Controller
@EnableAutoConfiguration
public class SampleController {

    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SampleController.class, args);
    }
}
  • 拆分步骤

在之前的文章中我们提到,SB启动分为两步,new SpringApplication对象和执行run方法。

// 第一步
        SpringApplication application = new SpringApplication(SpringBootApplication05.class);
        // 第二步 
        ConfigurableApplicationContext context = application.run(args);

第一步

创建对象后 返回SpringApplication对象,我们来分析此对象有用的几个方法。

构造方法

实例化SpringApplication对象

public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

通过构造方法 我们发现是可以传递多个class对象,即除了传递启动类以外,我们也可以传递其他Class对象 可以是@configuration注解包含的对象 当然也可以是其他注解类型的。

  • 示例

我们可以将UserService.class交给SpringBoot进行管理

SpringApplication application2=new SpringApplication(SpringBootApplication05_01.class,UserService.class);

addPrimarySources 方法

此种方式等价于构造方法方式。可实现多个class注入。

Set primarySources = new LinkedHashSet<>(Arrays.asList(SpringBootApplication05_01.class,UserService.class));
            application.addPrimarySources(primarySources);

setAdditionalProfiles

设置附加的Profiles,个人理解等价于Spring.profiles.active,使用方式如下

//默认执行application-dev.yml文件中的配置
  application.setAdditionalProfiles("dev");

setBannerMode

设置Banner工作模式 可关闭,也可以在控制台和log中,使用方式如下

application.setBannerMode(Banner.Mode.CONSOLE);// 控制台输出
application.setBannerMode(Banner.Mode.OFF);// 关闭输出

setBanner

设置banner样式,也可以通过spring.banner.location=https://gitee.com/bgt0314/mix_learn/raw/master/SpringBootDemo/src/main/resources/my.txt 来配置。

application.setBanner(new Banner() {
                @Override
                public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
                    out.println("////////////////////////////////////////////////////////////////////\n" +
                            "//                          _ooOoo_                               //\n" +
                            "//                         o8888888o                              //\n" +
                            "//                         88\" . \"88                              //\n" +
                            "//                         (| ^_^ |)                              //\n" +
                            "//                         O\\  =  /O                              //\n" +
                            "//                      ____/`---'\\____                           //\n" +
                            "//                    .'  \\\\|     |//  `.                         //\n" +
                            "//                   /  \\\\|||  :  |||//  \\                        //\n" +
                            "//                  /  _||||| -:- |||||-  \\                       //\n" +
                            "//                  |   | \\\\\\  -  /// |   |                       //\n" +
                            "//                  | \\_|  ''\\---/''  |   |                       //\n" +
                            "//                  \\  .-\\__  `-`  ___/-. /                       //\n" +
                            "//                ___`. .'  /--.--\\  `. . ___                     //\n" +
                            "//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n" +
                            "//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n" +
                            "//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n" +
                            "//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n" +
                            "//                           `=---='                              //\n" +
                            "//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n" +
                            "//         佛祖保佑       永无BUG     永不修改                    //\n" +
                            "//                                                    ricky制作   //\n" +
                            "////////////////////////////////////////////////////////////////////");
                }
            });

设置完毕后,springbootbanner变成上述的形式。

setLogStartupInfo

设置启动日志,默认true

/**
 *
 true的时候会多出下面两行日志  关闭后不打印这两行
 2018-05-17 10:24:50.585  INFO 20536 --- [           main] com.ricky01.SpringBootApplication05_01   : The following profiles are active: dev
 2018-05-17 10:24:50.697  INFO 20536 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@cd3fee8: startup date [Thu May 17 10:24:50 CST 2018]; root of context hierarchy

 */
application.setLogStartupInfo(false);

addInitializers

添加ApplicationContextInitializer类型的实例,在ConfigurableApplicationContext刷新之前初始化Spring ConfigurableApplicationContext的回调接口

application.addInitializers(new ApplicationContextInitializer<GenericApplicationContext>() {
                @Override
                public void initialize(GenericApplicationContext ctx) {
                    // 可以根据上下文提前设置一些参数
                    ctx.registerBean("rickyDefault",User.class,User::new); // 注入默认UserBean对象
                    ConfigurableListableBeanFactory beanFactory = ctx.getBeanFactory();
                    System.out.println(ctx.getBeanDefinitionCount());
                    ConfigurableEnvironment environment = ctx.getEnvironment();
                    System.out.println("ApplicationContextInitializer::::::::::"+environment.getPropertySources());

                }
            });

addListeners

添加监听事件

// 可以监听 ApplicationEvent的子类的事件  比如context刷新和关闭等等
            // 在application.properties中配置context.listener.classes=xxx 或者
            /**
             *
             @Component
            public class XXClass{
                @EventListener
                public void onApplicationEvent(ContextRefreshedEvent event) {
                System.out.println("哎哟 等价 我监听到了呢");
                }
            }
             */

            // 跟setListeners类似

        ApplicationListener<ContextRefreshedEvent> applicationListener = new ApplicationListener<ContextRefreshedEvent>() {

            @Override
            public void onApplicationEvent(ContextRefreshedEvent event) {
                System.out.println("哎哟,我是这个时候刷新完了:" + event.getTimestamp() + ",刷新后你要干啥呢?");
            }
        };
        application.addListeners(applicationListener);

第二步

run后我们可以操作的方法。

// 默认是如下  当然也可以转换成其他context比如logstart里面打印的AnnotationConfigServletWebServerApplicationContext
 ConfigurableApplicationContext context = application.run(args);
  • 前提,我们在启动类中注入如下对象
@Bean
    public User createUser(){
        return new User("ricky",10);
    }
    @Bean
    @Primary // 当使用类获取bean实例的时候使用
    public User createUser2(){
        return new User("ricky02",10);
    }

    @Bean("rickyUser") // 指定bean的名称
    public User createUser3(){
        return new User("ricky03",10);
    }
  • context.getBeansOfType

根据class获取bean对象,是个集合

// 获取所有的User的bean实例
System.out.println(context.getBeansOfType(User.class));
  • context.getBean(String beanName)

根据BeanName获取bean对象,是单个对象

// 获取beanName是createUser的bean对象
            System.out.println("createUser-----------------"+context.getBean("createUser"));
  • context.getBean(Class requiredType)

根据class获取bean对象,是单个对象,当有多个是需要使用@Primary

User defaultUser = context.getBean(User.class);
// 此例子是获取到的createUser2对象
            System.out.println("User.class-----------------"+defaultUser);
  • context.getBeanDefinitionNames()

获取已经装载的bean对象

String[] BeanDefinitionNames = context.getBeanDefinitionNames();
            System.out.print("包含的bean对象:");
           for (String name:BeanDefinitionNames){
               System.out.println(name+",");
           }
  • context.getApplicationName()

获取应用名称

String applicationName = context.getApplicationName();
            System.out.println("applicationName:"+applicationName);
  • context.getBeanDefinitionCount()

获取bean数量

int beannum=context.getBeanDefinitionCount();
            System.out.println("bean的数量:"+beannum);
  • context.publishEvent

发布ApplicationEvent 自定义的事件需要在此处发布

// 发布自定义事件
            context.publishEvent(new MyApplicationEvent(new Object()));
  • context.addApplicationListener

添加监听

// 等同上述 applicationListener
             context.addApplicationListener(applicationListener);
  • context.addBeanFactoryPostProcessor

添加BeanFactoryPostProcessor,但是此处无效,

// bean工厂加载完毕的后置通知  但是在这里无效  实现方式参照 createBeanDefinitionRegistryPost()方法
            context.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
                @Override
                public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                    System.out.println("--------------------------------"+beanFactory.getBeanDefinitionCount());
                }
            });

有效实现方式如下

@Bean
    public  BeanDefinitionRegistryPostProcessor createBeanDefinitionRegistryPost(){
        return new BeanDefinitionRegistryPostProcessor() {
            @Override
            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//                    BeanDefinitionBuilder builder=BeanDefinitionBuilder.rootBeanDefinition(User.class);
//                    registry.registerBeanDefinition("userBeanPost",builder.getBeanDefinition());

                System.out.println("----------#######postProcessBeanDefinitionRegistry------------------"+registry.getBeanDefinitionCount());
                RootBeanDefinition user=new RootBeanDefinition(User.class);
                registry.registerBeanDefinition("userBeanPost",user);
            }

            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                System.out.println("----------#######postProcessBeanFactory------------------"+beanFactory.getBeanDefinitionCount());
            }
        };
    }
  • context.close()

关闭应用。程序结束。

至此,常用的context我们已经演示完毕。

演示项目地址,欢迎fork和star

码云:SpringBootLearn

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java工会

Spring Boot 自动配置的 “魔法” 是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

9300
来自专栏Hongten

spring+hibernate+JQuery开发_电子相册_源码

=============================================================

52440
来自专栏微信公众号:Java团长

Spring Boot 自动配置的“魔法”是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

14520
来自专栏编码小白

tomcat源码解读四 tomcat中的processer

     Processor是一个接口,针对于不同协议下具有不同的具体实现类,其实现类的具体功能是处理http请求,主要是对协议进行解析,状态处理以及响应。然后...

47270
来自专栏精讲JAVA

Spring Boot 自动配置的 “魔法” 是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

12320
来自专栏技术专栏

深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰...

41010
来自专栏zhisheng

渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

上篇文章写了 ElasticSearch 源码解析 —— 环境搭建 ,其中里面说了启动 打开 server 模块下的 Elasticsearch 类:org.e...

14710
来自专栏技术墨客

Spring核心——IOC处理器扩展 原

Spring一直标注自己是一个非侵入式框架。非侵入式设计的概念并不新鲜,目标就是降低使用者和框架代码的耦合,毕竟框架的开发者和使用者几乎肯定不是同一个团队。Sp...

7420
来自专栏DT乱“码”

Memcached使用实例

package com.memcached.util; import java.io.BufferedWriter; import java.io.FileW...

24560
来自专栏拭心的安卓进阶之路

Android 进阶7:进程通信之 AIDL 的使用

记得 2015 年实习面试,笔试题里就有这道题:请介绍下 AIDL。 当时的我是懵逼的,只好老老实实空着。没想到后来面试时面试官大哥嘿嘿一笑说他也没用过这玩意,...

23280

扫码关注云+社区

领取腾讯云代金券