Java技术–Spring

Spring框架核心特性:

  • IOC(控制反转)容器:spring通过控制反转实现了对象的便捷管理,开发者只需要定义Bean和其依赖关系,由Spring来管理对象的构建。【不再需要繁杂的对象构建等】
  • AOP切面编程:开发者可以将许多相同逻辑的业务代码通过AOP来进行模块化,提高代码简洁性和降低耦合。
  • 事务管理:Spring提供了事务管理的接口,开发者可以轻松的使用@Transactional注解来声明事务
  • MVC架构:在Controller层采用 模型-视图-控制 来灵活的URL映射。

Spring IOC:

概述:

即控制反转,是一种对象控制的思想。原本对象的控制完全由开发者操持,而通过IOC反转为由spring容器智能的管理。

在SpringBoot框架中,一般采用依赖注入(DI)的方式,具体来说当需要创建对象时,不再需要繁琐的new关键字了,而只需要通过自动注入的方式便捷的得到这个对象。通过IOC的方式,大大的降低了对象与业务逻辑之间的耦合

IOC的实现方式:

通过配置或注解将所有需要IOC管理的Bean(如Service和Mapper)放进IOC容器

当程序启动,所有Bean扫描完成后,通过反射创建Bean的实例,但对象内部的所有属性仍是null(全是空指针)

Spring会检查所有类中的@Autowired或者@Resource注解,并且去IOC容器内部按类型或名字查找Bean,再通过反射在程序运行时动态的注入对象(通过注解找到对应的Bean,并且赋值)。

自动注入完成后动态代理对象会被容器存放到容器的缓存中,之后对此Bean的调用则直接从缓存中拿

(保持单例,因为本来Bean的实例全就是null,线程用一个Bean单例就可以了)

Spring AOP:

概述:

一种面向切面编程的思想,核心就是它是一种不侵入业务代码的重复逻辑解耦方案

主要作用是将逻辑重复但需要被业务代码共同调用的逻辑封装起来,通过注解的方式模块化的组合代码,降低业务耦合。

应用场景

  • @Transactional本质上就是AOP的实现。
  • 一些createTime的字段注入和日志记、异常处理,
  • 权限校验:在方法执行前通过@Before判断角色权限并动态的拼接SQL条件

AOP的动态代理机制:

任何AOP包括事务注解都需要使用动态代理对象(Proxy)。

当一个切面类指定一个Bean为AOP切面,即@Before(“execution(* com.yourpackage.UserService.*(..))”)

Spring就会将这个UserService增强为动态代理对象:

@Before userService.login()会先跳入@Before中,执行由开发者编写的逻辑,最后再调用login()方法从而完成切面。所以使用原始对象如this.login()会导致AOP失效(特别是事务失效),需要拿到并使用proxy.

深究动态代理:

实现了JDK接口或继承CGLIB代理类

普通的注解往往就是直接实现一个功能或者接口
而AOP可以通过注解的方式在业务代码之中插入一段被封装好的复杂重复逻辑代码.

但是这段复杂的逻辑代码的调用对象通过原始对象来调用会使得业务代码非常冗杂.

所以动态代理就可以包装一个原始对象的替身来执行这段冗杂的操作,从而达到和通过原始对象调用一样的效果

被动态代理增强的原始对象的所有调用,都会通过proxy显式的调用,而原始对象则隐式的执行。

Bean的循环依赖:

当Bean A完成实例化后,进行自动注入@Autowired Bean B时,Ioc容器转向Bean B。

同样发现Bean B自动注入@Autowired Bean A需要自动注入Bean A。

Bean的循环依赖就发生了。

通过Spring的三级缓存:

  • 一级缓存:存放构建完毕的Bean
  • 二级缓存:存放实例完成但未赋值的Bean
  • 三级缓存:存放实例化Bean的工厂方法

1.A在完成实例化后,将创建Bean A的工厂方法放入三级缓存之中。

2.此时A需要注入B(赋值操作)才能完成初始化,IOC则转向Bean B的初始化。

3.B在实例化后将工厂方法放入三级缓存。在B执行注入时发现B也需要注入A才能完成Bean B的初始化:

4.Ioc会前往缓存寻找A的Bean,最终在三级缓存找到了A的工厂方法,从而创建了一个A

5.此时将A放入二级缓存。完成Bean B的初始化并放入一级缓存。

6.之后再通过一级缓存的B完成Bean A的初始化。

如果A是动态代理对象,则在三级缓存中直接创建增强Bean A放入二级缓存。

当Bean A完成初始化之后再增强为代理对象时,直接从二级缓存拿。

因为动态代理对象的存在,所以必须要有三级缓存:

如果不使用三级缓存,而直接让Bean B去二级缓存拿A,只能拿到原始对象。而Bean A后续初始化完成需要被增强为动态代理对象,导致出现了两个A的实例,破坏了单例原则。

事务失效的场景:

  • 调用原始对象而非动态代理对象
  • @Transactional修师的方法为private (Spring AOP实现的API的要求)
  • 捕获了异常而未抛出,spring无法感知异常的发生而以为一切正常
  • 异常是受检异常类型,需要显式的声明回滚受检异常类型

Bean的生命周期:

  • 扫描:扫描哪些类需要通过IOC进行管理
  • 实例化:创建bean,此时尚未赋值
  • 赋值:通过@Autowired等注解注入bean属性
  • 名称设置:通过setBeanName设置Bean的名称
  • 工厂设置:通过setBeanFactory持有IOC容器中其他Bean的引用
  • 前置处理:对Bean进行一些包装
  • 初始化:完成Bean的初始化(实例化+赋值)
  • 后置处理:是否需要增强Bean为动态代理
  • 放入缓存:放入一级缓存,随时可用
  • 运行:
  • 销毁:@PreDestory,清理Bean

SpringBoot的自动装配原理:

SpringBoot的自动装配可以让开发者极大的减少繁琐的配置操作。

核心原理:通过@EnableAutoConfiguration注解,从spring.factories文件中加载大量的配置类,并结合@Conditional按需生效。

1.@SpringBootApplication:位于启动类的复合注解,其中的@EnableAutoConfiguration是启动自动装配的开关

2.@EnableAutoConfiguration注解内部的@Import注解扫描Jar包下的spring.factories(Spring工厂配置文件)

3.通过@Conditional注解的方式条件判断文件内哪些配置类需要被加载

SpringBoot是怎么做到开箱即用的:

  • 起步依赖:
    • 起步依赖是一种特殊的Mevan依赖,打包了一切SpringBoot所需的基础依赖。
      • 例如springBoot-starter-web就打包了MVC、Tomcat等Web应用所需的核心依赖
  • 自动配置:
    • 通过启动类的@EnableAutoConfiguration注解内部的@Import注解扫描Jar包下的Spring工厂配置文件
    • 通过@Conditional注解的方式判断哪些配置类需要被加载

MyBatis:

MyBaits的优点:

  • 与传统的JDBC相比,SQL与Java代码解耦
  • 支持动态SQL,动态的拼接if,where
  • 自动映射功能,减少很多冗余代码
  • 可以通过插件扩展功能,比如MyBatis-Plus
  • 与Spring生态集成,比如配置类中的@MapperScan

Mybatis里的 # 和 $ 的区别

  • 在MyBatis里的#{}内部写入SQL语句时,会被暂时替换成 ? ,当真正执行SQL语句时会替换?占位符,可以防止SQL注入
  • 而使用${}有SQL注入的风险

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇