原 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 条评论
登录 后参与评论

相关文章

来自专栏搜云库

Spring Boot 中使用 SolrCloud

Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库; Solr是以Lucene为基础实现的文本检索应用服务。Solr部署方式有单机方式、多机Ma...

2775
来自专栏wannshan(javaer,RPC)

dubbo通信消息解析过程分析(1)

由于rpc底层涉及网络编程接口,线程模型,网络数据结构,服务协议,细到字节的处理。牵涉内容较多,今天就先从一个点说起。 说说,dubbo通过netty框架做传...

3716
来自专栏码字搬砖

spark连接kafka工具类

版权声明:本文为博主原创,欢迎转载,转载请标明出处 Blog Address:http://blog.csdn.net/jsjsjs1789 ...

471
来自专栏与神兽党一起成长

jFinal路由解析源码分析

jFinal的路由解析是在JFinalFilter中做的,这个Filter也需要在web.xml中配置。JFinalFilter实现了javax.servlet...

792
来自专栏wannshan(javaer,RPC)

dubbo @Activate 注解使用和实现解析

Activate注解表示一个扩展是否被激活(使用),可以放在类定义和方法上,dubbo用它在spi扩展类定义上,表示这个扩展实现激活条件和时机。先看下定义: @...

3796
来自专栏菩提树下的杨过

struts2: 玩转 rest-plugin

近期使用struts2的rest-plugin,参考官方示例struts2-rest-showcase,做了一个restful service小项目,但官网提供...

2425
来自专栏开发技术

spring事务源码解析

  在spring jdbcTemplate 事务,各种诡异,包你醍醐灌顶!最后遗留了一个问题:spring是怎么样保证事务一致性的? 当然,spring事务内...

471
来自专栏IT笔记

JAVA实现一个简单的RPC+项目源码

论坛中说到聊一聊RPC远程过程调用协议 http://www.52itstyle.com/thread-22564-1-1.html RPC(Remote Pr...

4399
来自专栏小勇DW3

Mybatis使用动态代理实现拦截器功能

  拦截器顾名思义为拦截某个功能的一个武器,在众多框架中均有“拦截器”。这个Plugin有什么用呢?或者说拦截器有什么用呢?可以想想拦截器是怎么实现的。Plug...

782
来自专栏Spark生态圈

[spark streaming] ReceiverTracker 数据产生与存储

在Spark Streaming里,总体负责任务的动态调度是JobScheduler,而JobScheduler有两个很重要的成员:JobGenerator 和...

761

扫码关注云+社区