springBoot学习笔记(三)源码分析之springApplication初始化过程

SpringApplication

springboot 启动的main放中的SpringApplication.run(DemoApplication.class, args)中的run方法其实是调用了SpringApplication中的run方法。

  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

该方法分为两部分,第一部分为初始化SpringApplication,第二部分为run

初始化SpringApplication

		//将resourceLoader 置为null
		this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //把启动类applicaiton放入成员变量名为primarySources的set中
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //推断应用类型,后面会根据该变量初始化对应的环境,一般为servlet
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //初始化classpah下META-INF/spring.factory中已配置的ApplicaitonContextInitializer,通过反射进行初始化器的初始化。ApplicaitonContextInitializer是spring提供的一个接口,其作用spring容器在刷新之前,会回调initialize方法。
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //初始化classpah下META-INF/spring.factory中已配置的ApplicationListener,通过反射进行监听器的初始化。ApplicationListener可以对spring进行全生命周期的监听
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //根据调用栈,推断出main方法的类名
        this.mainApplicationClass = this.deduceMainApplicationClass();

1、推断应用类型,一般为servlet。
2、初始化ApplicaitonContextInitializer初始化器。
3、初始化监听器
4、获取main方法类名。

run方法

public ConfigurableApplicationContext run(String... args) {
		//记录程序运行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        //ConfigurableApplicationContext   spring的上下文
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        //1、获取并启动监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //2、构造应用上下文环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            //3、初始化应用上下文
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            //4、刷新应用上下文前的准备阶段
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //5、刷新应用上下文
            this.refreshContext(context);
            //6、刷新应用上下文后的拓展接口
            this.afterRefresh(context, applicationArguments);
            //记录时间停止
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

获取并启动监听器

  private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        //springApplicaitonRunListeners负责在springboot启动的不同阶段,广播出不同的消息,传递信息给ApplicationListener监听器实现类
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
    }

构造应用上下文环境

应用上下文环境:上下文,上下文代表了程序当下所运行的环境,联系你整个app的生命周期与资源调用,是程序可以访问到的所有资源的总和,资源可以是一个变量,也可以是一个对象的引用。

prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		//创建并配置相应环境
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        //根据用户配置,配置environment系统环境,通过判断应用类型,即SERVLET,来创建环境
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        //启动相应的监听器,其中一个重要的监听器ConfigFileApplicationListener就是加载项目配置文件的监听器
        listeners.environmentPrepared(environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

初始化应用上下文

beanFactory正是在AnnotationConfigServletWebServerApplicationContext实现的接口
GenericApplicationContext中定义的。在上面createApplicationContext()方法中的,
BeanUtils.instantiateClass(contextClass) 这个方法中,不但初始化了
AnnotationConfigServletWebServerApplicationContext类,也就是我们的上下文context,同样
也触发了GenericApplicationContext类的构造函数,从而IoC容器也创建了。

刷新应用上下文前的准备阶段

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		//设置容器环境
		context.setEnvironment(environment);
		//执行容器后置处理
		postProcessApplicationContext(context);
		//执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种 方式自定义的
		applyInitializers(context);
		//向各个监听器发送容器已经准备好的事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		//将main函数中的args参数封装成单例Bean,注册进容器
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		//加载启动类,将启动类注入容器
		load(context, sources.toArray(new Object[0]));
		//发布容器已加载事件
		listeners.contextLoaded(context);
	}

刷新应用上下文(IOC容器的初始化过程)

主要是执行AbstractApplicationContext类的refresh()方法。

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
        //刷新上下文环境
            this.prepareRefresh();
            //这里是在子类中启动refreshBeanFactory()的地方
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备bean工厂,以便在此上下文中使用
            this.prepareBeanFactory(beanFactory);

            try {
            //设置beanFactory的后置处理
                this.postProcessBeanFactory(beanFactory);
                //调用BeanFactory的后处理器,这些处理器是在Bean定义中向容器注册的
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册Bean的后处理器,在Bean创建过程中调用
                this.registerBeanPostProcessors(beanFactory);
                //对上下文中的消息源进行初始化
                this.initMessageSource();
                //初始化上下文中的事件机制
                this.initApplicationEventMulticaster();
                //初始化其他特殊的Bean
                this.onRefresh();
                //检查监听Bean并且将这些监听Bean向容器注册
                this.registerListeners();
                 //实例化所有的(non-lazy-init)单件
                this.finishBeanFactoryInitialization(beanFactory);
                //发布容器事件,结束Refresh过程
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 是一个快速开发框架,它提供了一系列的工具和插件,可以快速构建一个企业级的应用程序。而 Shiro 是一个强大而灵活的安全框架,可以提供身份验证、授权、密码加密、会话管理等功能。CAS 是一个单点登录(SSO)协议,可以实现用户在多个应用系统中使用同一个身份验证。 下面是一个简单的 Spring Boot + Shiro + CAS 的示例应用程序: 1. 创建一个 Spring Boot 应用程序,并添加依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.6.0</version> </dependency> ``` 2. 配置 Shiro: ```java @Configuration public class ShiroConfig { @Bean public CasRealm casRealm() { CasRealm realm = new CasRealm(); realm.setCasServerUrlPrefix("https://cas.example.com/cas"); realm.setCasService("https://myapp.example.com/cas"); realm.setDefaultRoles("user"); realm.setRoleAttributeNames("memberOf"); return realm; } @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(casRealm()); return manager; } @Bean public ShiroFilterFactoryBean shiroFilter() { ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean(); filter.setSecurityManager(securityManager()); filter.setLoginUrl("https://cas.example.com/cas/login?service=https://myapp.example.com/cas"); filter.setSuccessUrl("/home"); filter.setUnauthorizedUrl("/403"); filter.setFilterChainDefinitionMap(Collections.singletonMap("/**", "authc")); return filter; } } ``` 3. 配置 CAS: ```java @Configuration public class CasConfig { @Bean public CasAuthenticationFilter casAuthenticationFilter() { CasAuthenticationFilter filter = new CasAuthenticationFilter(); filter.setCasServerLoginUrl("https://cas.example.com/cas/login"); filter.setServerName("https://myapp.example.com/cas"); filter.setAuthenticationSuccessHandler(authenticationSuccessHandler()); filter.setAuthenticationFailureHandler(authenticationFailureHandler()); return filter; } @Bean public SimpleUrlAuthenticationSuccessHandler authenticationSuccessHandler() { SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler(); handler.setDefaultTargetUrl("/home"); handler.setAlwaysUseDefaultTargetUrl(true); return handler; } @Bean public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() { SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler(); handler.setDefaultFailureUrl("/login?error=true"); return handler; } @Bean public FilterRegistrationBean<CasAuthenticationFilter> casFilterRegistrationBean() { FilterRegistrationBean<CasAuthenticationFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(casAuthenticationFilter()); registration.addUrlPatterns("/*"); registration.setName("CAS Authentication Filter"); registration.setOrder(1); return registration; } @Bean public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() { ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> registration = new ServletListenerRegistrationBean<>(); registration.setListener(new SingleSignOutHttpSessionListener()); registration.setOrder(2); return registration; } @Bean public ServletRegistrationBean<Servlet> casValidationServletRegistrationBean() { ServletRegistrationBean<Servlet> registration = new ServletRegistrationBean<>(); registration.setServlet(new Cas20ProxyReceivingTicketValidationFilter()); registration.addUrlMappings("/cas/*"); registration.setName("CAS Validation Filter"); registration.setOrder(3); return registration; } } ``` 4. 创建一个 HomeController: ```java @Controller public class HomeController { @GetMapping("/home") public String home() { return "home"; } @GetMapping("/403") public String error403() { return "403"; } } ``` 5. 创建一个 CAS 认证服务器: ```java @SpringBootApplication public class CasServerApplication { public static void main(String[] args) { SpringApplication.run(CasServerApplication.class, args); } } ``` 6. 创建一个 CAS 客户端: ```java @SpringBootApplication @EnableScheduling public class CasClientApplication { public static void main(String[] args) { SpringApplication.run(CasClientApplication.class, args); } } ``` 这就是一个简单的 Spring Boot + Shiro + CAS 的示例应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值