精选了20行代码,让你看看SpringIoc的底层源码实现

精选了20行代码,让你看看SpringIoc的底层实现

Spring两大技术之一Ioc:就是用来帮助管理Bean的。
什么是Bean:所有交给Spring管理的对象都是Bean。
什么是交给Spring管理:(如下)

通过xml配置的<bean>标签
@Component@Service@Controller@Repository注解标注的
@Bean注解标注的
@Autowired自动注入的

除此之外,我们的对象都是普通对象,是从IoC里获取不到的,只能自己new。
那么问题来了,Spring是什么时候生成Bean的,又是怎样实现依赖注入的呢?

先show一个测试过程的debug日志,让你看看生成对象和注入依赖的过程
//先写一个配置类
@ComponentScan("com.zqq.questionnaire.Math.proxy.Ent")
@Configuration//@configuration,相当于xml里面的Beans
public class AppConfig {
    @Bean//@Bean相当于Bean标签
    public User user(){
        return new User(new Fox());
    }
}

@Component//把Fox交给Ioc容器管理
public class Fox {
    Fox(){
        System.out.println("this is a fox");
    }
    @Override
    public String toString() { return "Fox{}";}
}


@Component//User交给IoC容器管理
public class User {
    User(Fox fox){
        System.out.println(fox.toString());
        System.out.println("this is a user");
    }
    @Override
    public String toString() {return "User{}";}
}

//写一个测试类
public class SpringTest {
    public static void main(String[] args) {
        //Ioc容器初始化,并开始管理Bean和依赖关系
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
        //通过getBean获取一个对象
        System.out.println(context.getBean(User.class).toString());
    }
}

下面看一下debug日志

AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2c22f3
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
ClassPathBeanDefinitionScanner - Identified candidate component class: file [E:\ideaIU\tomcat\apache-tomcat-8.5.50\webapps\proj\Math\proxy\Ent\Fox.class]
ClassPathBeanDefinitionScanner - Identified candidate component class: file [E:\ideaIU\tomcat\apache-tomcat-8.5.50\webapps\Math\proxy\Ent\User.class]
DefaultListableBeanFactory - Overriding bean definition for bean 'user' with a different definition: replacing [Generic bean: class [com.zqq.questionnaire.Math.proxy.Ent.User]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [E:\ideaIU\tomcat\apache-tomcat-8.5.50\webapps\proj\questionnaire\questionnaire\target\classes\com\zqq\questionnaire\Math\proxy\Ent\User.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=user; initMethodName=null; destroyMethodName=(inferred); defined in com.zqq.questionnaire.Math.proxy.Ent.AppConfig]
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalPersistenceAnnotationProcessor'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'
DefaultListableBeanFactory - Creating shared instance of singleton bean 'fox'
this is a fox
DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
this is a fox
Fox{}
this is a user
User{}

从源码上分析IoC管理Bean的过程

//Ioc容器初始化,并开始管理Bean和依赖关系
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);

容器的构造函数有三个步骤,也就是说,生成和管理Bean就是在这三个步骤中

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
        //生成一个Reader读注解、生成一个Scanner浏览路径
    	//AnnotatedBeanDefinitionReader
    	//ClassPathBeanDefinitionScanner:用来确认候选的组件类Fox.class 和User.class
    this.register(componentClasses);
    	//for循环里面,使用AnnotatedBeanDefinitionReader注册
   		//this.registerBean(componentClass);
    this.refresh();
    	//通过refresh,destroy之前的Bean,重新create一个新的BeanFactory,也就是DefaultListableBeanFactory
    }

当有了工厂之后,管理Bean就开始了。
refresh里面有三个方法至关重要,生成了一些系统公用Bean

//这三句指令对应了之前Debug日志里,所有的Bean组件,断点查看
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.finishBeanFactoryInitialization(beanFactory);
	//就是第三句管理了自己注册的Bean

BeanFactory有一个属性是alreadyCreated,表示目前为止已经创建的Bean,可以在调试的时候查看,上面的前两行生成这样6个Bean,是Spring管理组件的公用的Bean。
在这里插入图片描述

//在finishBeanFactoryInitialization方法里面是这一句获取了Bean的单例
beanFactory.preInstantiateSingletons();

往下找,可以找到生成Bean的方法是AbstractAutowireCapableBeanFactory这个类的doCreatBean方法。
我抽取了几句关键代码,可以顺利的理清楚管理Bean和依赖注入的过程。(tab缩进的是方法的内部逻辑)

//获取BeanDefinition(类的描述,相当于菜谱)
RootBeanDefinition mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);

//获取BeanWrapper(一个工具,提供类的属性注入的方法)
instanceWrapper = this.createBeanInstance(beanName, mbd, args);

//获取未注入属性的空对象和class字节码
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();

//依赖注入或者说属性注入,就是对象变得丰满的过程
Object exposedObject = bean;

//调用populateBean注入依赖
this.populateBean(beanName, mbd, instanceWrapper);
	
	//方法一:可以根据名字获取
	this.autowireByName(beanName, mbd, bw, newPvs);
		//方法是:根据名字获取一个bean,加到一个属性链表里面
		Object bean = this.getBean(propertyName);
        pvs.add(propertyName, bean);
	
	//方法二:根据type获取
	 this.autowireByType(beanName, mbd, bw, newPvs);
	 	//根据type解析依赖,并加到属性链表里
        DependencyDescriptor desc = new AbstractAutowireCapableBeanFactory.AutowireByTypeDependencyDescriptor(methodParam, eager);
        Object autowiredArgument = this.resolveDependency(desc, beanName, autowiredBeanNames, (TypeConverter)converter);
        if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument);}
     
    //更新属性链表
    pvs = newPvs;
    
    //将新的属性应用到对象上,利用Definition作指示,用BeanWrapper提供方法
    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
    	
    	//内部是调用BeanWrapper,设置propertyValue
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));

//对赋值之后的Bean初始化,获取真正的Bean。
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
return exposedObject;

这里只是抽取了极少量的逻辑代码,用来说明Bean管理的过程,有兴趣的可以继续深入。
所以为什么说IoC是java 反射的一种表现呢,上面就体现的很清楚。
我们需要一个对象不再是new一个对象并调用,而是容器获取类的信息和构造器,构造object、setProperty,并把对象提供给我们。

原创文章 64 获赞 27 访问量 9409

猜你喜欢

转载自blog.csdn.net/weixin_44893585/article/details/105298904