概述
Spring容器源码解析
- DI和IOC
- IOC(控制反转)
- 提出问题
- 源码梳理
- `registerAnnotationConfigProcessors`类关键代码:构建工厂
- `registerAnnotationConfigProcessors`类关键代码:判断
- 图解![在这里插入图片描述](https://file2.kaopuke.com:8081/files_image/2023060822/2021051023052261.png)
- 文章总结
我们工作中经常用到Spring容器,一谈Spring都知道DI(依赖注入),IOC(控制翻转),但是少人认知Spring容器的体系是如何的
DI和IOC
IOC(控制反转)
控制:什么控制谁控制了谁?
在我们传统的认知中,A调用B一定会声明B,这个时候A就控制了B,这个就是控制。
反转:反转了什么?正转是什么?
正转:A能控制B的生命周期就是正转。
反转:B掌握自己的生命周期就是反转。
B如何掌握自己的生命周期,万物包一层,我们包一层容器,这个容器控制B的生命周期,称之为IOC(Inversion of Control)
IOC是种编程思想,通常我们创建对象会在类内部进行创建,这个时候我们这个类的生命周期则完全交于使用类,什么时候创建什么时候销毁我们无法控制,对于程序的堆栈管理不够清晰。如图:
2.DI(依赖注入)
依赖:依赖了什么东西?为什么依赖?
依赖于IOC容器,因为需要将容器里的东西创建进行
注入:注入了什么?为什么注入?
注入A类所需要的资源(类,静态属性之类的),因为外部资源类统一交由IOC容器管理,不由本类控制生命周期。
DI(ependency Injection)是控制反转衍生出来的一种解决方案,通过调用构造函数或者Set方法将方法注入进去。
提出问题
在Spring容器中,我们标注@Service,@Autowird为什么就创建了实例?@Lazy(true)如何实现延迟加载?
其实在之前的ORM脚手架文章的时候已经有一部分答案,这里将探讨Spring中是如何实现的。
源码梳理
已AnnotationConfigApplicationContext
解析
new AnnotationConfigApplicationContext("org.example.mvc");
进一步
发现调用的this关键字,this
就是调用自己的无惨构造函数
public AnnotationConfigApplicationContext(String... basePackages) {
this();
this.scan(basePackages);
this.refresh();
}
我们查看无参构造函数,发现又传入一个this
?
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
我们再次进入发现this其实是一个BeanDefinitionRegistry
接口
public interface BeanDefinitionRegistry extends AliasRegistry
我们Ctrl+H查看一下那些类实现了这个接口
我们发现AnnotainConfigApplicationContext
继承于GenericApplicationContext
实现于BeanDefinitionRegistry
当子类构造的时候,父类的构造函数会优先构造,因此我们去看GenericApplicationContext
类中的构造函数
public GenericApplicationContext() {
this.customClassLoader = false;
this.refreshed = new AtomicBoolean();
this.beanFactory = new DefaultListableBeanFactory();
}
发现这里新建了2个对象DefaultListableBeanFactory
和AtomicBoolean
public DefaultListableBeanFactory() {
this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
this.resolvableDependencies = new ConcurrentHashMap(16);
this.beanDefinitionMap = new ConcurrentHashMap(256);
this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
this.allBeanNamesByType = new ConcurrentHashMap(64);
this.singletonBeanNamesByType = new ConcurrentHashMap(64);
this.beanDefinitionNames = new ArrayList(256);
this.manualSingletonNames = new LinkedHashSet(16);
this.configurationFrozen = false;
}
我们发现这里都是初始化一些默认的自动匹配注入的一些东西,结合名字会可以认定一个初始化IOC容器
AtomicBoolean
是函数操作就没有必要截屏上来了
当前的类结构
我们看完上面后,回看后面AnnotatedBeanDefinitionReader
这个对象构建了什么东西
我们走进去后发现这段代码
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
这里名字的意思构建注解配置处理器,我们进去后发现它构建了一个工厂把后置处理器构建了进去
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
RootBeanDefinition def;
if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
}
//代码太多,占篇幅,截取了一部分实例,谢谢
return beanDefs;
}
代码太多,占篇幅,截取了一部分实例,谢谢
什么是后置处理器?
后置处理是抽象集中处理方法,不管具体类的核心的集中方法,就好比这样的代码
if(A instanceof B){
A.hello();
}
不过他会把注解标记了的Class
注入到Set
中
registerAnnotationConfigProcessors
类关键代码:构建工厂
在registerAnnotationConfigProcessors
方法还有个工厂创建的关键代码
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
我们走进去看看,是将registry
转为BeanFactory
工厂,这里传入的都是实现了BeanDefinitionRegistry
接口的方法,这里只有2个类AnnotainConfigApplicationContext
,GenericApplicationContext
@Nullable
private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
if (registry instanceof DefaultListableBeanFactory) {
return (DefaultListableBeanFactory)registry;
} else {
return registry instanceof GenericApplicationContext ? ((GenericApplicationContext)registry).getDefaultListableBeanFactory() : null;
}
}
这里有个getDefaultListableBeanFactory()
方法,
public final DefaultListableBeanFactory getDefaultListableBeanFactory() {
return this.beanFactory;
}
这个beanFactory()
方法是构建的DefaultListableBeanFactory
构造函数中构建的DefaultListableBeanFactory
,拿到这个Factory工厂后把后置器Processor
注入进去
registerAnnotationConfigProcessors
另一处关键代码,定义我们可以使用的注解代码 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
BeanDefinition
,是个什么?
继承了特性,作用域,这个BeanDefinitionHolder
就是我们的Bean都会转为这个对象
registerAnnotationConfigProcessors
类关键代码:判断
registry.containsBeanDefinition
的本质就是看工厂是否有这个Bean的存在,因此我们看BeanDefinitionRegistry
中的BeanDefinition getBeanDefinition(String var1)
方法
我们点击registry.containsBeanDefinition
看发现是接口BeanDefinitionRegistry
类
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;
void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String var1);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String var1);
}
GenericApplicationContext
类实现了BeanDefinitionRegistry
接口,前面registry
是传入的this
,也就是本类,本类没有实现这个方法,因此在继承的抽象方法中找到了,getBeanDefinition
方法,本质是抽象类帮忙构建的。
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
return this.beanFactory.getBeanDefinition(beanName);
}
图解![在这里插入图片描述](https://file2.kaopuke.com:8081/files_image/2023060822/2021051023052261.png)
文章总结
这篇主要讲解了IOC,DI,AnnotationConfigApplicationContext时创建的第一个对象的构建过程,构建后置对象的中工厂的注入和后置处理器的判断,顺带提了一下类会转为BeanDefinitionHolder
这个对象注入。需要自己一个一个顺着文章去看一遍就大概明白了。
没有代码。
最后
以上就是丰富乌龟为你收集整理的J2EE-026 Spring容器源码解析(一)构建后置处理器DI和IOC提出问题源码梳理文章总结的全部内容,希望文章能够帮你解决J2EE-026 Spring容器源码解析(一)构建后置处理器DI和IOC提出问题源码梳理文章总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复