zoukankan      html  css  js  c++  java
  • SpringBean

    Spring扫描配置过程

    当我们在Spring中指定component-scan之后,由ComponentScanBeanDefinitionParser将指定的xml装载成BeanDefinition,当然最终实现功能的还是ComponentScanBeanDefinitionScanner的doScan方法,ComponentScanBeanDefinitionParser的parse方法只是将配置文件写的包名转换为相对地址,然后由doScan方法执行装配任务

    ComponentScanBeanDefinitionParser.java

    @Nullable
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            String basePackage = element.getAttribute("base-package");
            basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
            String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ",; 	
    ");
            ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element);
            Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
            this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
            return null;
        }
    

    ComponentScanBeanDefinitionScanner.java

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
            String[] var3 = basePackages;
            int var4 = basePackages.length;
    
            for(int var5 = 0; var5 < var4; ++var5) {
                String basePackage = var3[var5];
                Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
                Iterator var8 = candidates.iterator();
    
                while(var8.hasNext()) {
                    BeanDefinition candidate = (BeanDefinition)var8.next();
                    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                    candidate.setScope(scopeMetadata.getScopeName());
                    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                    if (candidate instanceof AbstractBeanDefinition) {
                        this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
                    }
    
                    if (candidate instanceof AnnotatedBeanDefinition) {
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
                    }
    
                    if (this.checkCandidate(beanName, candidate)) {
                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                        beanDefinitions.add(definitionHolder);
                        this.registerBeanDefinition(definitionHolder, this.registry);
                    }
                }
            }
    
            return beanDefinitions;
        }
    

    Bean的创建过程

    1.实例化:当客户端向容器申请一个Bean时或者当容器在初始化一个Bean发现还需要依赖另一个Bean时,会将扫描到的信息以BeanDefinition的形式保存,使用BeanDefinition来实例化对应的Bean。

    2.设置对象属性注入(这里涉及到循环依赖问题):Spring通过BeanDefinition找到对象所依赖的其他对象,并将这个对象一并创建赋值

    3.处理Aware接口:Spring会检测实例化的这个类是否有实现Aware接口,如果实现了则去调用相对应的方法,例如常见的BeanNameAware、BeanClassLoader、BeanFactory、ApplicationContextAware

    4.BeanPostProcessor前置处理:当Bean实现BeanPostProcessor接口时,并重写了postProcessorBeforInitialization则会去调用这个方法

    5.InitializingBean:Spring检测如果实现了该接口,则会调用afterPropertiesSet方法,制定初始化逻辑

    6.init-method:或者@PostConstruct注解,如果Spring发现Bean配置了该属性或者注解,那么就会去调用这个方法,执行该方法的初始化逻辑。

    7.BeanPostProcessor后置处理:当Bean实现BeanPostProcessor接口时,并重写了postProcessorAfterInitialization则会去调用这个方法


    这时Bean就已经创建完成了


    8.DisposableBean:当Bean实现了这个接口,在对象销毁前就会调用该方法

    9.destroy-method:或者@PreDestroy注解,如果Spring发现Bean配置了该属性或者注解,那么就会去调用这个方法,执行该方法的销毁逻辑。

    循环依赖问题

    当A依赖B,B依赖A的时候,发生循环依赖问题,如果对于依赖注入时,使用的是构造器来注入的,那么可以使用@Lazy注解,来延迟加载,这样就可以在单例池中顺利创建。

    而如果使用的@Autowired注解,那么Spring就直接帮我们解决这个问题,使用了三级缓存解决的这个问题。

    首先先分析一下,当循环依赖发生的时候,单例池都没有相关的对象,且无法去直接new出来,那么就有了二级缓存,假如要创建一个A对象,但是单例池中没有对象B,那么就在二级缓存当中创建一个属性都为空的B对象,并把这个B注入到A中,此时单例池中就有了A对象,那么对象B就能直接创建了,这个时候A对象中的B属性就会被关联到单例池中的B,两个对象就创建完成。

    二级缓存只能解决普通对象的循环依赖,如果循环依赖的是一个有AOP切面的对象,如果还是这种二级缓存模型则无法将对象的代理对象创建出来,则引入了三级缓存,如果发生循环依赖且在单例池和二级缓存都找不到时,则去三级缓存查找是否有对应的AOP配置信息对象,如果查找到则去将这个对象提前进行AOP,然后将这个代理对象放入二级缓存,这个配置信息则从三级缓存中删除。

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//单例池
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);//三级缓存
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);//二级缓存
    
    @Nullable
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    synchronized(this.singletonObjects) {
                        singletonObject = this.singletonObjects.get(beanName);
                        if (singletonObject == null) {
                            singletonObject = this.earlySingletonObjects.get(beanName);
                            if (singletonObject == null) {
                                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                                if (singletonFactory != null) {
                                    singletonObject = singletonFactory.getObject();
                                    this.earlySingletonObjects.put(beanName, singletonObject);
                                    this.singletonFactories.remove(beanName);
                                }
                            }
                        }
                    }
                }
            }
    
            return singletonObject;
        }
    

    image-20210828222853181

  • 相关阅读:
    Hibernate学习笔记
    Servlet:从入门到实战学习(3)---Servlet实例【图文】
    Servlet:从入门到实战学习(2)---Servlet生命周期
    Servlet:从入门到实战学习(1)---全·环境配置
    java复习(9)---数据库JDBC
    java复习(8)---I/O
    java复习(7)---集合类、泛型
    java复习(6)---异常处理
    C#尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    C# TTS 文本转语音中断实现方式
  • 原文地址:https://www.cnblogs.com/haijie-wrangler/p/15201558.html
Copyright © 2011-2022 走看看