百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

很多人学Spring框架,总觉得IOC模糊不清?

lipiwang 2024-10-31 15:24 22 浏览 0 评论

前言

学习过Spring框架的人一定都会听过Spring的IOC(控制反转) 这个概念,对于初学Spring的人来说,总觉得IOC是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring IOC的理解。

读者福利:私信回复【111】获取整理好的spring全家桶学习笔记和面试题资料(1184页PDF文档)

IOC是什么

IOC——Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好IOC呢?理解好IOC的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

(1)谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

(2)为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

用图例说明一下,传统程序设计如图,都是主动去创建相关对象然后再组合起来:

当有了IOC的容器后,在客户端类中不再主动去创建这些对象了,如图所示:

接下来我们说一下IOC的4个特性

1. lazy-Init延迟加载

Bean对象的延迟加载(延迟创建)

ApplicationContext 容器的默认?为是在启动服务器时将所有 singleton bean 提前进?实例化。提前实例化意味着作为初始化过程的?部分,ApplicationContext实例会创建并配置所有的singleton bean。

1.1 XML方式开启延迟加载:

lazy-init="" 配置bean对象的延迟加载 ,true或者false false就是立即加载

<bean id="lazyResult" class="com.lagou.edu.pojo.Result" lazy-init="false"></bean>

我们先来看一下当lazy-init="false" 也就是立即加载的时候:

可以看到,在容器启动后,getBean之前,lazyResult这个bean已经存在了

然后我们把lazy-init="true",设置为true

然后我们F8往下走一步:

发现出现了lazyResult

1.2 注解开启延迟加载:

@Lazy

1.3全局配置——default-lazy-init="":

在bean的根标签中:

应用场景:

(1)开启延迟加载?定程度提?容器启动和运转性能
(2)对于不常使?的 Bean 设置延迟加载,这样偶尔使?的时候再加载,不必要从?开始该 Bean 就占?资源

2. FactoryBean和BeanFactory

2.1 BeanFactory

容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型,比如ApplicationContext

2.2 FactoryBean

spring中的bean有两种

  • 普通bean
  • 工厂bean(FactoryBean)
    可以生产某一个类型的bean实例(返回给我们),也就是说我们可以借助于它自定义bean的创建过程。

Bean创建的三种?式中的静态?法和实例化?法和FactoryBean作?类似,FactoryBean使?较多,尤其在Spring框架?些组件中会使?,还有其他框架和Spring框架整合时使?

//可以让我们自定义Bean的创建过程,完成复杂bean定义
public interface FactoryBean<T> {
 //返回FactoryBean创建的实例,如果isSingleton返回true,则该实例会放到Spring容器的单例缓存池中Map
 @Nullable
 T getObject() throws Exception;

    //返回FactoryBean创建的bean类型
 @Nullable
 Class<?> getObjectType();

 //返回作用域是否单例
 default boolean isSingleton() {
  return true;
 }
}

2.2.1 新建类CompanyFactoryBean,实现FactoryBean接口,并重写方法:

public class CompanyFactoryBean implements FactoryBean<Company> {
    private String companyInfo;//注入公司名称,地址,规模  以逗号分隔

    public void setCompanyInfo(String companyInfo) {
        this.companyInfo = companyInfo;
    }

    @Override
    public Company getObject() throws Exception {
        //创建复杂对象Company
        Company company=new Company();
        String[] split = companyInfo.split(",");
        company.setName(split[0]);
        company.setAddress(split[1]);
        company.setScale(Integer.parseInt(split[2]));

        return company;
    }

    @Override
    public Class<?> getObjectType() {
        //返回bean的类型
        return Company.class;
    }

    @Override
    public boolean isSingleton() {
        //是否是单例
        return true;
    }
}

public class Company {
    private String name;
    private String address;
    private int scale;
 //省略getset 和toString
}

2.2.2 xml文件中配置bean

<bean id="companyBean" class="com.lagou.edu.factory.CompanyFactoryBean">
   <property name="companyInfo" value="拉钩,中关村,500"></property>
</bean>

2.2.3 测试

    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object companyBean = applicationContext.getBean("companyBean");
        System.out.println(companyBean);
    }
//结果返回的是 Company{name='拉钩', address='中关村', scale=500}   

虽然在xml配置文件中配置的bean的class="com.lagou.edu.factory.CompanyFactoryBean" 但是返回的Company类型。

如何返回CompanyFactoryBean类型呢?


打印结果为:com.lagou.edu.factory.CompanyFactoryBean@545b995e

3. 后置处理器

Spring提供了两种后处理bean的扩展接?,分别为 BeanPostProcessorBeanFactoryPostProcessor,两者在使?上是有所区别的。

??初始化(BeanFactory)—> Bean对象

在BeanFactory初始化之后可以使?BeanFactoryPostProcessor进?后置处理做?些事情

在Bean对象实例化(并不是Bean的整个?命周期完成)之后可以使?BeanPostProcessor进?后置处理做?些事情

注意:对象不?定是springbean,?springbean?定是个对象

3.1 SpringBean生命周期图

按照上述描述的打印一下。看看是否一致:

//实现了BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean,DisposableBean接口
public class Result implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
    private String status;
    private String message;
 //省略getset toString方法

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4.BeanFactoryAware:"+beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3.BeanNameAware:"+name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5.ApplicationContextAware:"+applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("7.InitializingBean");
    }

    public void initMethodTest(){
        System.out.println("8.initMethod");
    }

    @PostConstruct
    public void postCoustrcut(){
        System.out.println("postCoustrcut");
    }

    //销毁之前执行
    @PreDestroy
    public void preDestroy(){
        System.out.println("销毁之前执行");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean");
    }
}

/**
    拦截实例化之后的对象(实例化了 并且属性注入了)
    拦截所有的
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("lazyResult".equalsIgnoreCase(beanName)){
            System.out.println("MyBeanPostProcessor before");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("lazyResult".equalsIgnoreCase(beanName)){
            System.out.println("MyBeanPostProcessor After");
        }
        return bean;
    }
}

//XML配置文件中:    
<bean id="lazyResult" class="com.lagou.edu.pojo.Result"  init-method="initMethodTest"></bean>

//测试:
    @org.junit.Test
    public void testBeanLazy(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Object lazyResult =  applicationContext.getBean("lazyResult");
        System.out.println(lazyResult);
        applicationContext.close();
    }

打印出:

4. 其他:

Spring系列的学习笔记和面试题,包含spring面试题、spring cloud面试题、spring boot面试题、spring教程笔记、spring boot教程笔记、最新阿里巴巴开发手册(63页PDF总结)、2020年Java面试手册。一共整理了1184页PDF文档。

资料获取方式:私信回复【111】获取上述资料

部分资料图片:

最后

欢迎大家一起交流,喜欢文章记得点赞转发哟!感谢支持!

相关推荐

一个简单便捷搭建个人知识库的开源项目(MDwiki)

这里我通过自动翻译软件,搬运总结MDwiki官网的部署和使用方法。第一步:下载编译好的后MDwiki文件,只有一个HTML文件“mdwiki.html”。第二步:在mdwiki.html同级目录创建“...

强大、简洁、快速、持续更新 PandaWiki新一代 AI 驱动的开源知识库

PandaWiki是什么PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答...

DeepWiki-Open: 开源版Deepwiki,可自己构建github文档库

Deepwiki是Devin团队开发的github文档库,用户能免费使用,但代码不是开源,而DeepWiki-Open侧是开源版本的实现。DeepWiki-Open旨在为GitHub和GitLa...

最近爆火的wiki知识管理开源项目PandaWiki

项目介绍PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答、AI搜索等...

轻量级开源wiki系统介绍(轻量开源论坛系统)

wiki系统有很多DokuWiki、MediaWiki、MinDoc等等都是开源的wiki系统。商业版的wiki,像很多企业在用的confluence等。今天我们讲的是一款轻量级且开源的文档管理系统:...

DNS解析错误要怎么处理(dns解析状态异常怎么办)

在互联网时代,网络已经成为人们生活和工作中不可或缺的一部分。然而,当遇到DNS解析错误时,原本畅通无阻的网络访问会突然陷入困境,让人感到十分困扰。DNS,即域名系统,它如同互联网的电话簿,将人们易于...

网页加载慢?这些方法让你秒开网页!

打开浏览器,信心满满地准备查资料、看视频或者追剧,却发现网页怎么都打不开!是不是瞬间感觉手足无措?别慌,这个问题其实挺常见,而且解决起来并没有你想象的那么复杂。今天就来聊聊网页打不开究竟是怎么回事,以...

windows11 常用CMD命令大全(windows11msdn)

Windows11中的命令提示符(CMD)是一个强大的工具,可以通过命令行执行各种系统操作和管理任务。以下是一些常用的CMD命令,按功能分类整理,供你参考:一、系统信息与状态systeminfo显...

电脑提示DNS服务器未响应怎么解决?

我们在使用电脑的时候经常会遇到各种各样的网络问题,例如最近就有Win11电脑用户在使用的时候遇到了DNS未响应的问题,遇到这种情况我们应该怎么解决呢?  方法一:刷新DNS缓存  1、打开运行(W...

宽带拨号错误 651 全解析:故障定位与修复方案

在使用PPPoE拨号连接互联网时,错误651提示「调制解调器或其他连接设备报告错误」,通常表明从用户终端到运营商机房的链路中存在异常。以下从硬件、系统、网络三层维度展开排查:一、故障成因分类图...

如何正确清除 DNS 缓存吗?(解决你访问延时 )

DNS缓存是一个临时数据库,用于存储有关以前的DNS查找的信息。换句话说,每当你访问网站时,你的操作系统和网络浏览器都会保留该域和相应IP地址的记录。这消除了对远程DNS服务器重复查询的...

网络配置命令:ipconfig和ifconfig,两者有啥区别?

在计算机网络的世界里,网络接口就像是连接你电脑和外部网络的桥梁,而网络配置则是确保这座桥梁稳固、通信顺畅的关键。提到网络配置工具,ipconfig和ifconfig绝对是两个绕不开的名字。它们一...

救急的命令 你会几个?(救急一下)

很多人都说小编是注册表狂魔,其实不完全是,小编常用的命令行才是重点。其实所谓的命令行都是当初DOS时代的标准操作方式,随着Windows不断演化,DOS的命令早已成为Windows的一部分了——开始菜...

电脑有网却访问不了GitHub原来是这样

当满心欢喜打开电脑,准备在GitHub这个“开源宝藏库”里挖掘点超酷的项目,却遭遇了网页无法访问的尴尬。看着屏幕上那令人无奈的提示,原本高涨的热情瞬间被泼了一盆冷水,是不是感觉世界都不美好了...

rockstargames更新慢| r星更新速度 怎么办 解决办法

rockstargames更新慢|r星更新速度怎么办解决办法说到RockstarGames,那可是游戏界的大佬,作品个顶个的经典。但话说回来,每当新内容更新时,那蜗牛般的下载速度,真是让人急得...

取消回复欢迎 发表评论: