当前位置:   article > 正文

spring面试题_每次http请求都会创建一个新的bean,该作用域仅适用于webapplicationcontext

每次http请求都会创建一个新的bean,该作用域仅适用于webapplicationcontext环境的
  1. bean 的作用域有哪些?
    在这里插入图片描述
    1.1 xml 方式注册 在最初开始的spring项目中 就是使用的这种方式注册bean
    1.2 使用注解注入
    在这里插入图片描述
    1.3 使用JavaApi的 方式
    自定义一个类,然后实现BeanDefinitionRegistryPostProcessor类
    重写里面的方法 然后新建一个类使用 BeanDefinitionRegistry 类的registerBeanDefinition 方法,设置bean的名字和实体类.代码如下
    在这里插入图片描述
    bean 的作用域一共有5个 设置方式都是为 scope=“类型”
    1. singleton作用域 默认全局是一个单独的Bean对象
    2. prototype作用域: 每次调用bean的时候都可以创建一个新的bean的实列
      top: 面试题:如何保证controller是线程安全的?在controller类上添加注解@Scope(“prototype”) 这样每次调用的时候都是一个新的bean
@Scope("prototype")
//@Scope(WebApplicationContext.SCOPE_REQUEST) 
//@RequestScope()
// WebApplicationContext.SCOPE_REQUEST== request    
// String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
//    String SCOPE_REQUEST = "request";
//    String SCOPE_SESSION = "session";
//    String SCOPE_APPLICATION = "application";
//    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
//    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
//    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述 3. request作用域:每次Http请求时都会创建一个新的 Bean该作用域仅适应于WebApplicationContext环境
4. session作用域:同一个Http Session共享-个Bean对象
不同的Session拥有不同的Bean对象,仅适用于WebApplicationContext环境
5. application作用域:
全局的Web作用域,类似于Servlet中的Application

  1. 什么是同名Bean?它是如何产生的?应该如何避免?
    每个Bean拥有一个或多个标识符,在基于XML的配置中,可以使用id或者name来作为Bean的标识符,通常Bean的标识符由字母组成,允许使用特殊字符,同一个Spring配置文件中Bean的id和name是不能够重复的,否则Spring容器启动时会报错.
    同名Bean指的是多个Bean有相同的name或者id
    Spring对待同名Bean的处理规则是使用最后面的Bean覆盖前面的Bean
    在定义Bean时,尽量使用长命名非重复的方式来定义
    Bean的id或name属性并非必须指定
    如果留空的话,容器会为Bean自动生成一个唯- -的名称
  2. Bean 的生命周期
    对于Spring Bean,并不是启动阶段就会触发Bean的实例化
    当客户端通过显式或者隐式的方式调用BeanFactory的getBean()方法时,才会触发该类的实例化方法
    对于BeanFactory,不是所有的getBean()方法都会实例化Bean对象
    例如作用域为singleton时,只会在第一次,实例化该Bean对象,之后会直接返回该对象
    如果使用的是ApplicationContext容器
    则会在该容器启动的时候,立即调用注册到该容器所有Bean的实例化方法
  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Creating instance of bean '" + beanName + "'");
        }

        RootBeanDefinition mbdToUse = mbd;
        //确定并加载bean的class
        Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
        // 验证以及准备需要覆盖的方法
            mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException var9) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
        }

        Object beanInstance;
        try {
        // getBeanPostProcessors 一个机会来返回代理对象来代替真正的Bean实例,在这里实现创建代理对象功能
            beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
            if (beanInstance != null) {
                return beanInstance;
            }
        } catch (Throwable var10) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
        }	
        try {
        	//创建bean
            beanInstance = this.doCreateBean(beanName, mbdToUse, args);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Finished creating instance of bean '" + beanName + "'");
            }

            return beanInstance;
        } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
            throw var7;
        } catch (Throwable var8) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
        }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

doCreateBean 的源码

   protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
   //实例化bean, BeanWrapper对象提供了设置和获取属性值的功能
        BeanWrapper instanceWrapper = null;
        //如果RootBeanDefinition 是单例,则移除未完成的FactoryBean实例的缓存
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
        // 创建bean实列
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
//获取BeanWrapper中封装的Object对象,其实就是bean对象的实例
        Object bean = instanceWrapper.getWrappedInstance();
      	//获取BeanWrapper中封装bean的Class
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
//应用MergedBeanDefinitionPostProcessor后处理器,合并bean的定义信息
//Autowire等注解信息就是在这步完成预解析,并且将注解需要的信息放入缓存
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
//为了避免循环依赖,在bean初始化完成前,就将创建bean 实例的ObjectFactory放入工厂缓存(singletonFactories)
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
		// 对bean 属性进行赋值
        Object exposedObject = bean;

        try {
            this.populateBean(beanName, mbd, instanceWrapper);
            // 调用初始化方法 如 init-method 注入aware对象 
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        if (earlySingletonExposure) {
        // 如果存在循环依赖 当前bean被其他类在初始化的过程中扫描过
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
            // 如果exposedObject 没有在其他方法中被增强过
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                //依赖检测
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
	// 如果actualDependentBeans 不为空 则表示依赖的bean没用被创建完,还存在循环依赖 
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            // 注册DisposableBean 以便在销毁时调用
           this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

在这里插入图片描述

bean 的初始化会自动调用方法initializeBean() ,在之前的博客中也记录到过,想要对一个bean初始化完成后做一些扩展 只需要实现一个
InitializingBean 接口类,重写一个他的 afterPropertiesSet () 方法,就能实现.下面是 initializeBean 方法源码

 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
            // 重点方法,根据beanName 对这个bean对象进行扩展
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

invokeAwareMethods 方法源码

 private void invokeAwareMethods(String beanName, Object bean) {

        if (bean instanceof Aware) {
         // 如果当前的bean类型是属于BeanNameAware 那么将当前的beanName 设置到BeanNameAware 中
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }
			// 如果当前的bean类型是属于BeanClassLoaderAware 那么将当前对象的classloader 注册到当前实例对象的beanClassLoader 中
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }

            if (bean instanceof BeanFactoryAware) {
                //是将当前对象注册到BeanFactory 中,这个对象就能获得一个beanFactory 对象的引用.
			((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

invokeInitMethods 方法源码如下

 protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
       // 判断当前bean是否实现了InitializingBean 接口 如果是的话,需要调用afterPropertiesSet 方法
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
			// 如果安全模式不为空,则进入if
            if (System.getSecurityManager() != null) {
                try {
                // 初始化方法
                    AccessController.doPrivileged(() -> {
                        ((InitializingBean)bean).afterPropertiesSet();
                        return null;
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
	// 如果安全模式为空则进入 else
	           ((InitializingBean)bean).afterPropertiesSet();
            }
        }
// 判断是否指定了init - method 
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
            // 利用反射机制执行指定方法
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

如果是BeanFactory容器,需要主劫调用destroySingletons()方法
通知BeanFactory容器去执行相应的销毁方法
如果是ApplicationContext容器,需要主劫调用registerShutdownHook()方法 告知ApplicationContext 容器执行相应的销毁方法
源码版本:Spring 5.2.2.RELEASE

在这里插入图片描述
Bean对象的生命周期在这里插入图片描述
IOC 是什么
在这里插入图片描述在这里插入图片描述
DI 的理解
在这里插入图片描述

SpringIOC 的优点

1.使用方便,拿来即用 无需显式的创建和销毁的过程.
2. 提供众多服务 比如事务管理、消息服务等
3. 提供单例模式的支持
4. 提供AOP抽象 利用它实现权限拦截、运行期监控等功能
5. 更符合面向对象的设计法则
6. 低侵,入式设计 代码污染极低 降低业务对象替换的复杂性

SpringIOC 的注入方法
1.构造方法注入
主要是依赖于构造方法去实现,构造方法可以是有参的也可以是无参的我们平时new对象时就是通过类的构造方法来创建类对象的
每个类对象默认会有一个无参的构造方法

构造器注入
在这里插入图片描述
注意 这里的xml 里面的属性是 constructor 构造器的意思 和用set方法设置值是不一样的
在这里插入图片描述

2.set注入
这里的key-Value 是property -value 不是构造器注入
在这里插入图片描述

3.接口注入
接口注入方式是比较古老的注入方式
因为它需要被依赖的对象实现不必要的接口,带有侵入性
因此现在已经被完全舍弃

Spring AOP目前提供了三种配置方式
1.基于Java API的方式
1.1 先定一个普通的类 ,自定义一个方法
在这里插入图片描述
1.2 定义一个方法类实现接口
实现接口MethodBeforeAdvice,AfterReturningAdvice 并重写方法
在这里插入图片描述
在这里插入图片描述
1.3 配置xml
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.基于 @AspectJ (Java) 的方式
2.1 添加引用依赖

<!--        添加 aop 的依赖-->
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId> aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2 开启注解
在这里插入图片描述
两种方式二选其一
2.3 自定义Aspect
普通的方法切面

@Component
@Aspect
public class ControllerAop {

    @Pointcut("execution(* com.myself.seckill.service.impl.OrderServiceImpl.*(..)) ")
    public void myCut()  {

    }

    @Before("myCut()")
    public void before(){
        System.out.println("before--->");
    }

    @After("myCut()")
    public void after(){
        System.out.println("after--->");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

基于注解的方式进行切面
首先自定义一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAop {
    String value() default "";
}
  • 1
  • 2
  • 3
  • 4
  • 5

再自定义基于注解的拦截器


@Aspect
@Component
public class MyLogAopAspect {
    //注解的方式 @annotation 表达式 , 方法或者类用 execution 表达式
    @Pointcut("@annotation(com.myself.seckill.myaop.MyLogAop)")
    public void MyPointCut(){

    }

    @Before("MyPointCut()")
    public void MyBefore(){
        System.out.println("MyBefore---> MyPointCut--->");
    }

    @After("MyPointCut()")
    public void MyAfter(){
        System.out.println("MyAfter---> MyPointCut--->");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

最后在启动类上添加注解

//开启aop切面的注解
@EnabledAspectJAutoProxy 
  • 1
  • 2

使用方法
在任何想要实现自定义注解切面的方法上添加自定义注解
在这里插入图片描述
加上一开始的自定义的切面
在这里插入图片描述
当访问这个接口的时候,效果如下
在这里插入图片描述
3. 基于XML 的方式
在这里插入图片描述

在这里插入图片描述
代理类的源码如下

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// isOptimize 是否等待优化 默认false ,isProxyTargetClass 是否是代理对象
        if (IN_NATIVE_IMAGE || !config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
            // 如果目标类不是一个接口类并且不是一个代理类 那么就直接创建一个CGlib代理对象 否则就创建一个JDK代理对象
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }

//  没有用户提供的代理接口 判断有没有获取代理接口的类 
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
    }


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

spring 自带的监控功能
在这里插入图片描述
springboot 内置tomcat 他是如何启动的?

直接上源码

 public ConfigurableApplicationContext run(String... args) {
 		// 1.创建并启动计时监控类
 		// 此计时器是为了监控并记录Spring Boot应用启动的时间它会记录当前任务的名称,然后开启计时器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        // 2.此过程声明应用上下文对象 
        ConfigurableApplicationContext context = null;
        //3.设置系统属性headless的值 设置Java.awt.headless = true,
        //其中awt (Abstract Window Toolkit)含义是抽象窗口工具集,
        //设置为true表示运行一-个headless服务器可以用它来作一-些简单的图像处理
        this.configureHeadlessProperty();
        //4. 创建所有Spring运行监听器并发布应用启动事件 此过程用于获取配置的监听器名称并实例化所有的类  在这个步骤之中就已经 进行了 实例化异常报告器 getSpringFactoriesInstances  它调用的是getSpringFactoriesInstances()方法来获取配置异常类的名称 并实例化所有的异常处理类
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
        //5. 处理args参数 声明并创建一个应用参数对象
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //	6.准备环境 创建配置并且绑定环境(通过property sources和profiles等配置文件)
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            // 7.创建banner的打印类  Spring Boot启动时会打印Banner图片
            Banner printedBanner = this.printBanner(environment);
            //8.创建应用上下文 根据不同的应用类型来创建不同的ApplicationContext.上下文对象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            // 准备应用上下文 此方法的主要作用是把.上面已经创建好的对象,传递给prepareContext来准备上下文 例如将环境变量environment对象绑定到.上下文中、配置bean生成器以及资源加载器记录启动日志等操作.
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //刷新应用上下文 此方法用于解析配置文件,加载bean对象,并且启动内置的web容器等操作
            this.refreshContext(context);
            //应用上下文刷新之后的事件的处理  此版本的源码中 此段代码为空方法
            this.afterRefresh(context, applicationArguments);
            //停止计时监控类 停止此过程第-步中的程序计时器,并统计任务的执行信息
            stopWatch.stop();
            //输出日志记录执行主类名、时间信息 把相关的记录信息,如类名、时间等信息进行控制台输出
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
			// 发布应用上下文启动完成事件 触发所有SpringApplicationRunListener监听器的started事件方法
            listeners.started(context);
            // 执行所有Runner运行器 执行所有的ApplicationRunner和CommandLineRunner运行器
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
        //发布应用上下文就绪事件 触发所有的SpringApplicationRunListener监听器的running事件
            listeners.running(context);
            // 返回应用上下文对象 
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

spring 源码中怎么解决的循环依赖?那些情况下无法解决循环依赖?

无论是spring框架 还是普通的Java对象 , 在初始化过程是都是先根据属性创建对象,然后再对属性赋予默认值. 在spring源码中. 在bean对象的创建的生命周期中通过三级缓存的方式,解决了常见的 普通循环依赖.当代码存在以下情况时 ,无法解决循环依赖的.如

@Service
public class A {

    @Autowired
    public B b;

    public A(B b) {
        this.b = b;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@Service
public class B {
    
    @Autowired
    public A a;

    public B(A a) {
        this.a = a;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

A、B 两个serverice 中的构造器相互依赖.

@Service
public class A {

    @Autowired
    public B b;

    public A(B b) {
        this.b = b;
    }
    
    @Async
    public void m1(){
        
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

A service中有 @Async注解修饰的方法

@Service
@Scope("prototype")
public class A {

    @Autowired
    public B b;

    public A(B b) {
        this.b = b;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A service中 的作用域范围是 prototype

出现这些情况的解决方法是在循环依赖的类上加一个@Lazy注解,表示延迟加载.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/86799
推荐阅读
相关标签
  

闽ICP备14008679号