浅入 spring ioc 单例容器

我们要干嘛?

1, 分析IOC 是怎么扫描路径

2, 对象是怎么被加载进容器的

3, 对象是怎么从容器里获取

4, 执行方法

案例代码,

网上一大顿分析xml的, 太low了, 我们直接从注解模式, 开始起飞

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext("com.test.first.ioc");
    HelloService bean = context.getBean(HelloService.class);

    String res = bean.hello();
    System.out.println(res);
}

@Service
public class HelloService {
    public String hello(){
        return "hello";
    }
}

来吧同志吗, 让我们开始, 记住我们要有目的性, 不用深究一个IF的意义

AnnotationConfigApplicationContext.java
class AnnotationConfigApplicationContext extends GenericApplicationContext {
    
    public AnnotationConfigApplicationContext(String... basePackages) {
        // 2, 调用默认构造器
        this();
        // 3, 扫描包
        this.scan(basePackages);
        // 4, 刷新IOC
        this.refresh();
    }
    
    // 1, 我们要分析, 父类构造器
    public GenericApplicationContext() {
        /**
         * 这便是 IOC 工厂实例了, 可以去看看
         * 而在这个 DefaultListableBeanFactory 父类 DefaultSingletonBeanRegistry
         * 中的属性 singletonObjects 便是我们常用的 单例容器了
         */
		this.beanFactory = new DefaultListableBeanFactory();
	}
    
    /**
     * 这全是一些参数赋值, 对象封装, 就不往下跟
     * 等到用到的时候, 我在去把它是怎么生成的, 挖出来
     */
    public AnnotationConfigApplicationContext() {
        /**
         * 封装了一个变量寄存器, 类加载器, 环境变量, 向 IOC 容器中注册一些基础bean
         * 哎, 为什么这个不分析呢,  哥们主要这不是我们的bean呀, 想看的话, 等我们分析完
         * bean的注册, 自己返过头来看, 便很清楚了
         */
		this.reader = new AnnotatedBeanDefinitionReader(this);
        
        // 加入一些基础扫描注解, component, 元信息缓存工厂
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
}

scan
class AnnotationConfigApplicationContext {
    
    public void scan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        // 1, 调用扫描器
        this.scanner.scan(basePackages);
    }
}

class ClassPathBeanDefinitionScanner {
    
    public int scan(String... basePackages) {
        // 在 AnnotationConfigApplicationContext 初始化的时候就已经扫描了一些包了
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

        // 2, 实际扫描
        doScan(basePackages);

        // Register annotation config processors, if necessary.
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

        // 总数 - 之前已经扫描的数量 = 本次实际扫描数量
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }
    
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {

            // 3, 这个集合装了一个bean定义set, 想都不用想, 这个地方是重点, bean 就是通过 bean 定义生成的
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            
            // ...
        }
        return beanDefinitions;
    }
}

findCandidateComponents(basePackage);

这部分代码有点小多, 拆出来的, 语义为扫描符合规则的组件


// 1
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    // this.componentsIndex 这个玩意貌似是一个指针, 不在本次研究范围
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        // 我们走这个分支, 
        return scanCandidateComponents(basePackage);
    }
}

// 2
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {

        // 解析路径
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;

        // 这个是一个文件路径集合, 一个个的类
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            if (resource.isReadable()) {
                try {

                    // 这个地方有意思了哦,  把class 的全七八糟的信息全扫描出来了, 并且缓存了元信息, 不然下次又得用的时候, 又扫描多费劲啊
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

                    // 判断是不是在我们应该扫描的范围类, 大部分都是被 Service 也有 Component, 当然在我们扫描访问
                    if (isCandidateComponent(metadataReader)) {

                        // 3, 创建一个通用bean定义
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                    }
                }
            }
        }
    }
    return candidates;
}


// 4 
class ScannedGenericBeanDefinition extends GenericBeanDefinition{
    public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
		Assert.notNull(metadataReader, "MetadataReader must not be null");
        // 注解信息
		this.metadata = metadataReader.getAnnotationMetadata();
        // 保存了class 信息
		setBeanClassName(this.metadata.getClassName());
	}
}

可以看到这个 破 ScannedGenericBeanDefinition 才这么点信息, 肯定不对劲, 后面肯定还有操作的呀,

我们接着往下分析

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {

        // 1, 上面的代码就分析这个的
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

        for (BeanDefinition candidate : candidates) {
		
			// 组件的作用域
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
			
			// 生成 bean 名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			
            if (candidate instanceof AbstractBeanDefinition) {
				// 2, 处理bean定义, 设置一些基础信息
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
				// 3, 设置懒加载, 一些描述信息
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
			
			// 容器中有没有存在的 bean 定义, 防止重复扫描, 进入容器
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				
				// 4, 这个地方有意思了, 根据scope 会生成代理对象, 但我们没有配置scope , 我们不配
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                
				beanDefinitions.add(definitionHolder);
				
				// 注册 bean 定义
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

// 5 , 最终会来到 IOC 工厂
class DefaultListableBeanFactory {

	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {        
        
		// 判断容器中在不在, 很简单是不是 = _ =
		BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            // ..
            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (this.hasBeanCreationStarted()) {
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    // ...
                }
            } else {
                // ...
            }
            this.frozenBeanDefinitionNames = null;
        }
		// ...
    }
}

到此我们的 bean 扫描已经结束, 所有的 bean class 信息已经全部放在了 IOC 当中, 那我们的对象了, 现在只是一堆描述啊? 好回到我们最开始的地方,

refresh() 刷新容器, 描述变对象

我们的目的是分析, 对象是怎么进入 容器的, 一定要记得我们的目的, 别看偏了哦

public AnnotationConfigApplicationContext(String... basePackages) {
    this();
    // 1, 上面的代码就是在分享, bean 定义是怎么来的
    scan(basePackages);
    // 2, 现在就要用 bean 定义生成对象了
    refresh();
}

class AbstractApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        
        // 东西好多是吧, 记得我们的目的
        synchronized (this.startupShutdownMonitor) {
            // 准备刷新, 记录开始时间, 校验环境参数
            prepareRefresh();

            // 获取我们的 IOC 工厂DefaultListableBeanFactory
            // 为什么是 ConfigurableListableBeanFactory , 答: 向下转级了
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

           	/**
             *  忽略一些对象注册, 注册一些默认对象
             */
            prepareBeanFactory(beanFactory);

            try {
                // ...不在本次探讨范围
                
                // 3, 主要是这个, bean 工厂的初始化
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }
			// ... 省略
        }
    }
    
    // 4
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		
		// 最后一行代码, 准备实例化单例对象
		beanFactory.preInstantiateSingletons();
	}
}

class DefaultListableBeanFactory {
    public void preInstantiateSingletons() throws BeansException {
        // 拿到bean定义名称循环
        List<String> beanNames = new ArrayList(this.beanDefinitionNames);
        while(true) {
            String beanName;
            Object bean;
            do {
                while(true) {
                    // 5, 获取一个bean
                    this.getBean(beanName);
                }
            } while(!(bean instanceof FactoryBean));

            // ....省略
        }
    }
    
    public Object getBean(String name) throws BeansException {
        // 6, 继续往深了调用
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }
    
    // 
    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
        // 获取一个实例
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        if (sharedInstance != null && args == null) {
           	// 存在就又会返回
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else if (mbd.isSingleton()) {
            
            // 7, 否则新建
            sharedInstance = this.getSingleton(beanName, () -> {
                try {
                    // 创建方法对象, 可以在组件默认构造器中断点即可跟踪
                    return this.createBean(beanName, mbd, args);
                } catch (BeansException var5) {
                    this.destroySingleton(beanName);
                    throw var5;
                }
            });
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        return bean;
    }
    
    // 8
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {

                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                if (newSingleton) {
                    // 加入单例容器
                    this.addSingleton(beanName, singletonObject);
                }
            }

            return singletonObject;
        }
    }
}
getBean

我们就带着这个目的去看, 这个对象是怎么来的

public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext("com.test.first.ioc");
    
    // 分析这个代码
    HelloService bean = context.getBean(HelloService.class);
    
    String res = bean.hello();
    System.out.println(res);
}

getBean 最终会调用到 IOC 工厂当中

class DefaultListableBeanFactory {
    
    public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
        
        // 会从 singletonObjects 取出返回回来
        NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args);
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        } else {
            BeanFactory parent = this.getParentBeanFactory();
            if (parent != null) {
                return args != null ? parent.getBean(requiredType, args) : parent.getBean(requiredType);
            } else {
                throw new NoSuchBeanDefinitionException(requiredType);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值