浅谈spring核心

       

我们都知道spring的两大核心是:IoC(控制反转)和AOP(面向切面编程);还有现在微服务时期,springCloud,springBoot,spring三者的关系;本文主要想阐述一下对这两个问题的理解,如有错误,恳请指正;

一、SpringCloud,SpringBoot,Spring三者的关系

Spring与SpringBoot的关系
简单的讲SpringBoot是基于Spring框架,是Spring的升级版,SpringBoot相比Spring的优势:简化了Maven依赖;本来需要xml的配置,可以用注解来进行配置等;通过再封装并屏蔽掉复杂的配置和实现原理,最终给开发者提供了一套简单易懂、易部署、易维护的分布式系统开发工具包。
发明 Spring Boot 不是为了取代 Spring,是为了让人们更容易的使用 Spring。

SpringBoot与SpringCloud的关系
Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发。服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。Spring Cloud 是基于 Spring Boot 开发的一套微服务架构下的服务治理方案。

总的来说,SpringCloud 是基于 SpringBoot,而 SpringBoot 是基于 Spring。

二、Spring的两大核心是:IoC(控制反转)和AOP(面向切面编程);

先抛开Spring这两个核心,在初学 Java 时,我们理所当然得会写出这样的代码:

我们把一些逻辑封装到 ServiceB 中,当 ServiceA 需用到这些逻辑时候,在 ServiceA 内部 new 个ServiceB 。
如果 ServiceB 封装的逻辑非常通用,还会有 ServiceC…ServiceF等都需要依赖它,也就是说代码里面各个地方都需要 new 个ServiceB ,这样一来如果它的构造方法发生变化,你就要在所有用到它的地方进行代码修改。

比如 ServiceB 实例的创建需要 ServiceC ,代码就改成这样:

确实有这个问题。

但实际上如若我们封装通用的service 逻辑,没必要每次都 new 个实例,也就是说单例就够了,我们的系统只需要 new一个 ServiceB 供各个对象使用,就能解决这个问题。

看起来好像解决问题了,其实不然。
当项目比较小时,例如大学的大作业,上面这个操作其实问题不大,但是一到企业级应用上来说就复杂了。
因为涉及的逻辑多,封装的服务类也多,之间的依赖也复杂,代码中可能要有ServiceB1、ServiceB2…ServiceB100,而且相互之间还可能有依赖关系。

抛开依赖不说,就拿 ServiceB单纯的单例逻辑代码,重复的逻辑可能需要写成百上千份。

且扩展不易,以前可能 ServiceB 的操作都不需要事务,后面要上事务了,因此需要改 ServiceB 的代码,嵌入事务相关逻辑。

没过多久 ServiceC 也要事务,一模一样关于事务的代码又得在 ServiceC 上重复一遍,还有D、E、F…

对几个 Service 事务要求又不一样,还有嵌套事务的问题,总之有点麻烦。

忙了一段时间满足事务需求,上线了,想着终于脱离了重复代码的噩梦可以好好休息一波。

紧接着又来了个需求,因为经常要排查线上问题,所以接口入参要打个日志,方便问题排查,又得大刀阔斧操作一波全部改一遍。

有需求要改动很正常,但是每次改动需要做一大堆重复性工作,又累又没技术含量还容易漏,这就不够优雅了。

 1.IOC(控制反转);

所以,我们想这样实现,我们只关心 ServiceA 依赖 ServiceB,但 ServiceB 是如何生成的我们不管,由那个“东西”帮我们生成它且关联好 ServiceA 和 ServiceB。

这个“东西”就是Spring 管理的对象代码以及那些 XML 文件(或标注了@Configuration的类)。
现在的逻辑是,ServiceA 具体依赖哪个 ServiceB,我们不需要显示的在代码中写上完整的关于如何创建 ServiceB 的逻辑,我们只需要写好配置文件,具体地创建和关联由 Spring 帮我们做。

举个Spring 里关于数据库的配置:

可以看到我们的图纸写的很清楚,创建 mybatis 的MapperScannerConfigurer需要告诉它两个属性的值,比如第一个是sqlSessionFactoryBeanName,值是 sqlSessionFactory。

而sqlSessionFactory又依赖 dataSource,而 dataSource 又需要配置好 driverClassName、url 等等。

所以,其实我们心里很清楚一个ServiceA(Bean)要创建的话具体需要什么东西,只不过这个创建过程由 Spring 代劳了,我们只需要清楚的告诉它即可。

因此,不是说用了 Spring 我们不再关心 ServiceA 具体依赖怎样的 ServiceB、ServiceB具体是如何创建成功的,而是说这些对象组装的过程由 Spring 帮我们做好。

我们还是需要清楚地知道对象是如何创建的,因为我们需要画好正确的图纸告诉 Spring。

所以 Spring 其实就是一台机器,根据我们给它的图纸,自动帮我们创建关联对象供我们使用,我们不需要显示得在代码中写好完整的创建代码。

这些由 Spring 创建的对象实例,叫作 Bean。

我们如果要使用这些 Bean 可以从 Spring 中拿,Spring 将这些创建好的单例 Bean 放在一个 Map 中,通过名字或者类型我们可以获取这些 Bean。

这就是 IOC。
ps:SpringBoot中就少了很多这种xml配置,基本用注解或者其他方式;所以spring中bean的xml配置的方式,更有助于初学者理解IOC。

ps:SpringBoot中就少了很多这种xml配置,基本用注解或者其他方式;所以spring中bean的xml配置的方式,更有助于初学者理解IOC;

 2.AOP(面向切面编程);

 也正因为这些 Bean 都需要经过 Spring 这台机器创建,不再是懒散地在代码的各个角落创建,我们就能很方便的基于这个统一收口做很多事情。

比如当我们的 ServiceB 标注了 @Transactional 注解,由 Spring 解析到这个注解就能明白这个 ServiceB 是需要事务的,于是乎织入的事务的开启、提交、回滚等操作。

但凡标记了 @Transactional 注解的都自动添加事务逻辑,这对我们而言减轻了太多重复的代码,只要在需要事务的方法或类上添加 @Transactional 注解即可由 Spring 帮我们补充上事务功能,重复的操作都由 Spring 完成。

再比如我们需要在所有的 controller 上记录请求入参,这也非常简单,我们只要写个配置,告诉 Spring xxx路径(controller包路径)下的类的每个方法的入参都需要记录在 log 里,并且把日志打印逻辑代码也写上。

Spring 解析完这个配置后就得到了这个命令,于是乎在创建后面的 Bean 时就看看它所处的包是否符合上述的配置,若符合就把我们添加日志打印逻辑和原有的逻辑编织起来。

这样就把重复的日志打印动作操作抽象成一个配置,Spring 这台机器识别配置后执行我们的命令完成这些重复的动作。

我们对Spring 的由来和核心概念有了一定的了解,基于上面的特性能做的东西有很多。有了 Spring 这个机器统一收口处理,我们就可以灵活在不同时期提供很多扩展点,比如配置文件解析的时候、Bean初始化的前后,Bean实例化的前后等等。所以就要用到Spring 全家桶,它提供的这些扩展和封装可以灵活地满足我们的诸多需求,而这些灵活都是基于 Spring 的核心 IOC 和 AOP 而来的。

ps:有兴趣的可以了解Spring 全家桶;

再来简单描述下 Spring 的原理:
Spring 根据我们提供的配置类和XML配置文件,解析其中的内容,得到它需要管理的 Bean 的信息以及之间的关联,并且 Spring 暴露出很多扩展点供我们定制,如 BeanFactoryPostProcessor、BeanPostProcessor,我们只需要实现这个接口就可以进行一些定制化的操作。

Spring 得到 Bean 的信息后会根据反射来创建 Bean 实例,组装 Bean 之间的依赖关系,其中就会穿插进原生的或我们定义的相关PostProcessor来改造Bean,替换一些属性或代理原先的 Bean 逻辑。

最终创建完所有配置要求的Bean,将单例的 Bean 存储在 map 中,提供 BeanFactory 供我们获取使用 Bean。

使得我们编码过程无需再关注 Bean 具体是如何创建的,也节省了很多重复性地编码动作,这些都由我们创建的机器——Spring帮我们代劳。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值