首页 > 编程语言 >Java面试——SpringBoot篇

Java面试——SpringBoot篇

时间:2024-09-03 15:05:44浏览次数:8  
标签:初始化 Java SpringBoot 容器 对象 class 面试 Bean public

前置知识

ApplicationContextInitializer

ApplicationContextInitializer是Spring框架中的一个扩展接口,用于在应用程序上下文(ApplicationContext)创建之前对其进行自定义初始化。通过实现该接口,您可以在应用程序上下文启动之前执行一些额外的配置或准备工作。

应用场景

  • 动态加载配置:通过实现ApplicationContextInitializer,您可以在应用程序上下文创建之前加载一些动态的配置,例如从外部配置文件中读取配置信息并注入到Spring的环境中。
  • 执行额外的初始化逻辑:如果您有一些需要在应用程序上下文启动之前执行的初始化逻辑,例如初始化数据库连接池或启动一些后台任务,您可以通过实现ApplicationContextInitializer来实现这些逻辑。

使用方式

1.定义ApplicationContextInitializer的实现类MyApplicationContextInitializer,进行属性注入
public class MyApplicationContextInitializer implements ApplicationContextInitializer{
    //ioc容器对象创建完毕后执行
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext){
        //给上下文context对象注入环境属性
        //1.准备属性
        Map<String,Object>myMap new HashMap<>();
        myMap.put("applicationName","big-event');
        //2,获取一个属性资源管理对象
        //获取的环境对象
        ConfigurableEnvironment environment applicationContext.getEnvironment();
        //属性资源管理对象
        MutablePropertySources propertySources environment.getPropertySources();
        /13.注册
        propertySources.addLast(new MapPropertySource(name:"myMap",myMap));
    }
}

2.在META-lNF/spring.factories配置文件中配置自定义的类

# 接口全路径名称=自定义类的全路径名称
org.springframework.context.ApplicationContextInitializer=com.itheima.initializer.MyApplicationContextInitializer

3.在启动类中获取注入的属性

@SpringBootApplication
public class App {
    public static void main(String[]args){
        ConfigurableApplicationContext context = SpringApplication.run(App.class,args);
        String applicationName context.getEnvironment().getProperty("applicationName");
        System.out.println(applicationName);
}

ApplicationListener

监听容器发布的事件,允许程序员执行自己的代码,完成事件驱动开发,它可以监听容器初始化完成、初始化失败等事件。通常情况下可以使用监听器加载资源,开启定时任务等

使用方式

public class MyListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event){
        //ApplicationEvent event对应的就是发布的事件,ApplicationReadyEvent,ApplicationFailedEvent
        if (event instanceof ApplicationReadyEvent){
            //容器初始化成功
            System.out.println("MyListener..容器初始化成功...");
        }
        if (event instanceof ApplicationFailedEvent){
            //容器初始化失败
            System,out.println("MyListener.,.容器初始化失购,.");
        }
    }
}
org.springframework.context.ApplicationListener=com.itheima.listener.MyListener

BeanFactory

Bean容器的根接口,提供Bean对象的创建、配置、依赖注入等功能

使用方法

@SpringBootApplication
public class App {
    public static void main(String[]args){
        ConfigurableApplicationContext context = SpringApplication.run(App.class,args);I
         
        //AnnotationConfigServletWebServerApplicationContext
        System.out.println(context.getClass());
        
        App appBean = context.getBean(App.class);
        System.out.println(appBean);
}

BeanDefinition

用于描述Bean,包括Bean的名称,Bean的属性,Bean的行为,实现的接口,添加的注解等等,Spring中,Bean在创建之前,都需要封装成对应的BeanDefinition,然后根据BeanDefinitioni进一步创建Bean对象。

使用方式

@Component//Bean对应的信息回封装到ScannedGenericBeanDefinition
public class User
}
@Configuration
public class MyConfig{
    @Bean
    public String aa(){
        return"我爱所有的美女";
    }
}
@SpringBootApplication
public class App {
    public static void main(String[]args){
        ConfigurableApplicationContext context = SpringApplication.run(App.class,args);I
         
         //获取BeanDefinition对象
        ConfigurableListableBeanFactory beanFactory context.getBeanFactory();
        BeanDefinition userBdf beanFactory.getBeanDefinition(beanName:"user");
        BeanDefinition aaBdf beanFactory.getBeanDefinition(beanName:"aa");
        System.out.println(userBdf.getclass()); //ScannedGenericBeanDefinition
        System.out.println(aaBdf.getclass()); //ConfigurationClassBeanDefinition
}

BeanFactoryPostProcessor

Bean工厂后置处理器,当BeanFactory.准备好了后(Bean初始化之前),会调用该接口的postProcessBeanFactory)方法,经常用于新增BeanDefinition。

使用方式

public class Teacher {
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
    //当beanFactory被实例化好后(bean创建之前),回调这个函数,注册一些BeanDefinition
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException{
        //注册一个Teacher的BeanDefinition
        GenericBeanDefinition gbdf new GenericBeanDefinition();
        gbdf.setBeanClass(Teacher.class);
        //向下强转
        DefaultListableBeanFactory dbf (DefaultListableBeanFactory)beanFactory;
        dbf.registerBeanDefinition(beanName:"teacher",gbdf);
    }
}
@SpringBootApplication
public class App {
    public static void main(String[]args){
        ConfigurableApplicationContext context = SpringApplication.run(App.class,args);I
         
         System.out.println(context.getBean(name:"teacher"));
}

Aware

感知接口,Spring提供的一种机制,通过实现该接口,重写方法,可以感知Spring应用程序执行过程中的一些变化。Spring会判断当前的Bean有没有实现Aware接口,如果实现了,会在特定的时机回调接口对应的方法。

使用方法

@Component
public class Student implements BeanNameAware,BeanclassLoaderAware,BeanFactoryAware{
    //BeanclassLoader的回调方法
    @Override
    public void setBeanclassLoader(CLassLoader classLoader){
        System.out.println("Student...setBeanclassLoader..."+classLoader);
    }
    //BeanFactoryAware的回调方法
    @Override
    public void setBeanFactory(BeanFactory beanFactory)throws BeansException
    System.out.println("Student...setBeanFactory..."+beanFactory);
}
//BeanNameAware的回调方法
@Override
public void setBeanName(String name){
System.out.println("Student...setBeanName..."+name);
}
}

InitializingBean/DisposableBean

+ 初始化接口,当Bean被实例化好后,会回调里面的函数,经常用于做一些加载资源的工作 + 销毁接口,当Bean被销毁之前,会回调里面的函数,经常用于做一些释放资源的工作

使用方法

@Component
public class Animal implements InitializingBean,DisposableBean{

    //PostConstructor,PreDestroy,提供初始化方法和销毁方法的注解
    @PostConstruct
    public void initMethod(){
        System.out.println("Animal...PostConstruct..initMethod");
    }
    @PreDestroy
    public void destroyMethod(){
        System.out.println("Animal...PreDestroy..destroyMethod");
    }

    //手动实现初始化方法和销毁方法
    //销毁方法
    @Override
    public void destroy()throws Exception{
        System.out.println("Animal...destroy...");
    }
    //初始化方法
    @Override
    public void afterPropertiesSet()throws Exception{
        System.out.println("Animal...afterPropertiesSet...");
    }
}

BeanPostProcessor

Bean的后置处理器,当Bean对象初始化之前以及初始化之后,会回调该接口对应的方法

使用方法

@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
    //初始化之前调用
    @Override
    public Object postProcessBeforeInitialization(Object bean,String beanName)throws BeansException{
        System.out.println("MyBeanPostProcessor...postProcessBeforeInitialization..."+beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean,beanName);
    }

    //初始化之后调用
    @Override
    public object postProcessAfterInitialization(object bean,String beanName)throws BeansException{
        System.out.println("MyBeanPostProcessor...postProcessAfterInitialization..."+beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean,beanName);
    } 
}

面试题

SpringBoot启动流程

总:SpringBoot启动,其本质就是加载各种配置信息,然后初始化Ioc容器并返回

分:在其启动的过程中会做这么几个事情
首先,当我们在启动类执行SpringApplication.run这行代码的时候,在它的方法内部其实会做两个事情
1.创建SpringApplication对象;
2.执行run方法。
其次,在创建SpringApplication对象的时候,在它的构造方法内部主要做3个事情。
1.确认web应用类型,一般情况下是Servlet类型,这种类型的应用,将来会自动启动一个tomcat
2.从spring.factories配置文件中,加载默认的ApplicationContextInitializer和ApplicationListener
3.记录当前应用的主启动类,将来做包扫描使用
最后,对象创建好了以后,再调用该对象的run方法,在run方法的内部主要做4个事情
1.准备Environment对象,它里面会封装一些当前应用运行环境的参数,比如环境变量等等
2.实例化容器,这里仅仅是创建ApplicationContext对象
3.容器创建好了以后,会为容器做一些准备工作,比如为容器设置Environment、BeanFactoryPostProcessor后置处理器,并且加载主类对应的Definition
4.刷新容器,就是我们常说的referesh,在这里会真正的创建Bean实例

总:总结一下我刚说的,其实SpringBoot启动的时候核心就两步,创建SpringApplication对象以及run方法的调用,在run方法中会真正的实例化容器,并创建容器中需要的Bean实例,最终返回。

IOC容器初始化流程

总:IOC容器的初始化,核心工作是在AbstractApplicationContext..refresh,方法中完成的

分:在refresh方法中主要做了这么几件事

1.准备BeanFactory,在这一块需要给BeanFacory设置很多属性,比如类加载器、Environment等

2.执行BeanFactory后置处理器,这一阶段会扫描要放入到容器中的Bean信息,得到对应的BeanDefinition(注意,这里只扫描,不创建)》

3.是注册BeanPostProcesor,,我们自定义的BeanPostProcessor就是在这一个阶段被加载的,将来Bean对象实例化好后需要用到

4.启动tomcat

5.实例化容器中实例化非懒加载的单例Bean,这里需要说的是,多例Bean和懒加载的Bean不会在这个阶段实例化,将来用到的时候再创建

6.当容器初始化完毕后,再做一些扫尾工作,比如清除缓存等

总:简单总结一下,在IOC容器初始化的的过程中,首先得准备并执行BeanFactory后置处理器,其次得注册Bean后置处理器,并启动tomcat,.最后需要借助于BeanFactory完成Bean的实例化

Bean的生命周期

总:Bea的生命周期总的来说有4个阶段,分别有创建对象,初始化对象,使用对象以及销毁对象,而且这些工作大部分是交给Bean工厂的doCreateBean方法完成的

分:

首先,在创建对象阶段,先调用构造方法实例化对象,对象有了后会填充该对象的内容,其实就是处理依赖注入

其次,对象创建完毕后,需要做一些初始化的操作,在这里涉及到几个扩展点。

1.执行Aware感知接口的回调方法

2.执行Bean后置处理器的postProcessBeforelnitialization方法

3.执行InitializingBean接口的回调,在这一步如果Bean中有标注了@PostConstructi注解的方法,会先执行它

4.执行Bean后置处理器的postProcessAfterlnitialization

把这些扩展点都执行完,Bean的初始化就完成了

接下来,在使用阶段就是程序员从容器中获取该Bean使用即可

最后,在容器销毁之前,会先销毁对象,此时会执行Disposable Bean接口的回调,这一步如果Bean中有标注了@PreDestroy接口的函数,会先执行它

总:简单总结一下,Bea的生命周期共包含四个阶段,其中初始化对象和销毁对象我们程序员可以通过一些扩展点执行自己的代码

Bean循环依赖

总:Bean的循环依赖指的是A依赖B,B又依赖A这样的依赖闭环问题,在Springl中,通过三个对象缓存区来解决循环依赖问题,这三个缓存区被定义到了DefaultSingletonBeanRegistry中,分别是singletonObjects用来存储创建完毕的Bean,earlySingletonObjects用来存储未完成依赖注入的Bean,还有SingletonFactories用来存储创建Bean的ObjectFactory。假如说现在A依赖B,B依赖A,整个Bean的创建过程是这样的

分:

首先,调用A的构造方法实例化A,当前的A还没有处理依赖注入,暂且把它称为半成品,此时会把半成品A封装到一个ObjectFactory中,并存储到springFactories缓存区

接下来,要处理A的依赖注入了,由于此时还没有B,所以得先实例化一个B,同样的,半成品B也会被封装到ObjectFactory中并存储到springFactory缓存区

紧接着,要处理B的依赖注入了,此时会找到springFactories中A对应的ObjecFactory,调用它的getObject方法得到刚才实例化的半成品A(如果需要代理对象,则会自动创建代理对象,将来得到的就是代理对象),把得到的半成品A注入给B,并同时会把半成品A存入到earlySingletonObjects中,将来如果还有其他的类循环依赖了A,就可以直接从earlySingletonObjects中找到它了,那么此时springFactories中创建A的ObjectFactory也可以删除了。

至此,B的依赖注入处理完了后,B就创建完毕了,就可以把B的对象存入到singletonObjects中了,并同时删除掉springFactories中创建B的ObjectFactory

B创建完毕后,就可以继续处理A的依赖注入了,把B注入给A,此时A也创建完毕了,就可以把A的对象存储到singletonObjects中,并同时删除掉earlySingletonObjects中的半成品A

截此为止,A和B对象全部创建完毕,并存储到了singletonObjects中,将来通过容器获取对象,都是从singletonObejcts中获取

总:总结起来还是一句话,借助于DefaultSingletonBeanRegistry的三个缓存区可以解决循环依赖问题

SpringMvc执行流程

总:使用了SpringMvc后,所有的请求都需要经过DispatcherServlet前端控制器,该类中提供了一个doDispatch方法,有关请求处理和结果响应的所有流程都在该方法中完成

分:

首先,借助于HandlerMapping处理器映射器得到处理器执行链,里面封装了HandlerMethod代表目标Controller的方法,同时还通过一个集合记录了要执行的拦截器。

接下来,会根据HandlerMethod获取对应的HandlerAdapter处理器适配器,里面封装了参数解析器以及结果处理器。

然后,执行拦截器的preHandle方法。

接下来是核心,通过HandlerAdapter处理器适配器执行目标Controller的方法,在这个过程中会通过参数解析器和结果处理器分别解析浏览器提交的数据以及处理Controller方法返回的结果。

然后,执行拦截器的postHandle方法。

最后处理响应,在这个过程中如果有异常抛出,会执行异常的逻辑,这里还会执行全局异常处理器的逻辑,并通过视图解析器ViewResolver解析视图,再渲染视图,最后再执行拦截器的afterCompletion。

标签:初始化,Java,SpringBoot,容器,对象,class,面试,Bean,public
From: https://www.cnblogs.com/cymxd/p/18391593

相关文章