我们要干嘛?
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);
}
}
}
}