spring-猜源码

1 前言(个人理解)

1 spring的思想总是先收集数据(成员变量或者方法)封装好,后面在某个地方去使用

2 任何类都会变成beandefinition,这是类的初始化,就像从java文件到class文件必须要编译器,再到class对象必须要类加载器一样,再变成bean,就必须先变成bd,里面是类的定义,实例化只有一个入口那就是getBean(),这样类的生命周期就很清晰明了

3 beanpostProcesser 是一种扩展点思想,在bean的初始化(beanFactoryPostProesser)到实例化 伴随着各种beanPostProdcessor通过接口实现扩展和插拔

我们学习spring就是学习思想放到平时工作中,猜的意思就是我们来设计怎么设计

猜@Bean怎么实现(结论1)

我们一般在一个类中自定义创建一个第三方类,在上面打一个注解

@Configuration
public class MyStarterConfig {

    @Bean
    public MyStarerBean myStarerBean(){
        return new MyStarerBean();
    }
}

就会注入一个这个你new的对象 但怎么做到的 我们猜下,前提是知道bd中是通过factory-method属性来实例化的

1 在扫描器扫描到MystarerConfig的时候,扫描到该注解看到是@bean注解,就好把这个注解的信息封装成一个元数据,再初始化为一个bd,然后将该bd的factory-name变成方法名,fatory-method变成该方法

2 在实例化这个bd的时候 就会调用到这个方法进行创建

源码验证:  

ConfigurationClassParser
       this.processImports(configClass, sourceClass, this.getImports(sourceClass), true);
        importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            String[] resources = importResource.getStringArray("locations");
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            String[] var19 = resources;
            int var21 = resources.length;

            for(int var22 = 0; var22 < var21; ++var22) {
                String resource = var19[var22];
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }

        Set<MethodMetadata> beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
        Iterator var17 = beanMethods.iterator();

的确是封装成了一个 MethodMetadata,先收集 再使用

同理我们可以猜@value,因为这个是打在成员变量上,跟@Resoure一样,那我们可以大胆推测也是在ioc之前通过一个beanPostprocessor像收集@Resource去收集这个注解,然后在ioc的时候去注入

2 猜mybatis和feign之类的实现类怎么注入spring(结论2)

前提是基于fatoryBean实现的

1  扫描到mybatis的mapper肯定要先把它变成一个bd,然后它的factoty-bean属性就是mybatisFatoryBean

2 实例化的时候 再调用它的getObject方法进行实例化

源码验证:

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        Iterator var3 = beanDefinitions.iterator();

        while(var3.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
            GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface");
            }

            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            definition.setBeanClass(this.mapperFactoryBean.getClass());
package org.mybatis.spring.mapper;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.StringUtils;

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

    public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }

所以不管怎样 都要先变成bd 再实例化

3  bean创建中怎么选择构造器和收集属性和aop的实现(结论3)

在实例化的时候 怎么去创建和对属性注入

前提是知道aop基于beanPostProessor的后置方法

1 创建一个beanPostProcessor来进行推断构造器(多个构造器),才能进行反射创建,这里为啥要做成接口等以后再理解

2  创建一个beanPostProcessor来进行属性收集 方便进行属性注入,做成接口是不同注解对应不同实现类

3 我们可以在创建一个beanPostProessor专门做代理  在实例化之后或者之前 都可以对这个bean生成代理,因为生成代理不是创建bean的主流程 所以做成扩展点,在实例化的时候顺便有需求就代理下

源码验证

public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }

    }
AbstractAutoProxyCreator
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值