Spring的Ioc的理解

前两篇文章中,大致分析了spring是如何注册、创建、实例化bean的。

搞清楚这些之后,其实对于Ioc的理解就特别清楚了。

Ioc(控制反转)也叫DI(依赖注入),个人觉得依赖注入比较好理解,因为从前两篇文章可以知道,spring完成的工作就是实例化Bean,在实例化该Bean的过程中,其依赖的另一个Bean才被设置进来或者创建。所以依赖注入比较好理解一些。

官方文档解释如下:

官方文档

所以Spring完成的工作基本是两大部分

1、创建bean对象:官方创建bean对象的文档地址

创建一个对象时,可以使用构造器、静态工厂、实例工厂这三种方式 

官方文档部分

2、实例化对象:官方文档依赖注入的部分

实例化对象的时候对于对象里面的属性如何设置呢?要么通过set方法设置进去、要么就是构造器

依赖注入

搞清楚这些,spring的基本运作方式就很清晰了,至于其他的,只不过就是spring对不同bean进行的管理、和使用方面的的不同了

 

小思考:

现在平时工作中,基本很少用到xml配置了,而且业务中如果有很多bean,写xml文件无疑是很痛苦的。那spring是如何把我们需要的bean,在容器启动之后注册进去的呢?

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注册扫描,不需要显式的写bean标签了-->
    <context:component-scan base-package="com.learn.spring.spring01.service"/>
    <!--<bean id="schoolService" class="com.learn.spring.spring01.service.SchoolServiceImpl">-->

    <!--</bean>-->
</beans>
@Component
public class SchoolServiceImpl {

    public String getTimeStr(){
      return   LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:MM:ss"));
    }

    public String getInStr(String str){
        return str;
    }
}

 

开启注解扫描之后,同时在bean上加入Component、Service等注解,就不需要显式的写bean标签了。

spring具体怎么做的呢

在解析xml文件、注册bean时parseBeanDefinitions方法判断当前标签不是xml的bean标签,而是context标签,则会调用parseCustomElement方法->handler.parse->pare方法如下:

public BeanDefinition parse(Element element, ParserContext parserContext) {
        String basePackage = element.getAttribute("base-package");
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ",; \t\n");
        ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element);
// 关键的两行
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
        this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
        return null;
    }

doScan方法会扫描xml文件配置的包路径下的类,如果是有注解,则会进入最后一个判断,进行beanDefinition的注册,调用的方法和过程和第一篇说的一毛一样

if (this.checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
// 注册bean
                    this.registerBeanDefinition(definitionHolder, this.registry);
                }

下面的registerComponents是做一些额外的工作,主要工作还是在doScan中完成的。

进一步思考:现在的springboot又是如何扫描的呢?

@Component注解已经默认放在了@SpringbootApplication注解里面了,至于springboot是怎么实现的,可以自行debug查看,原理都是相通的

我听到的我会忘记,我看到的我会记住,我做过才会明白。

所以有的时候对某个概念不熟悉、不理解,自己动动手debug一下,结合官方文档基本能很快的理解。死记硬背还是不靠谱的

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值