Mybatis
原理
JDK(动态代理)
MapperProxyFactory中,使用JDK的动态代理生成Mapper接口的代理代理类(代理对象)
代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回。
每一个 、、、 标签,都会被解析为一个 MappedStatement 对象。
mybatis的优点
简单易学,减少了大量的jdbc代码,消除了代码的冗余,有较好的数据库兼容性,提供了分页的插件,支持动态sql。
缺点:sql编写工作量大时,对开发人员要求较高。
sql依赖于数据库,导致可移植性差,不能随意更改数据库
在mybatis中,${} 和 #{} 的区别是什么?
#{} 是占位符,预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
mybatis是一个持久层框架,他避免了大量JDBC的代码,让我们开发人员只用注重写sql语句跟做简单的xml配置
mybatis的开发步骤
1、 创建SqlSessionFactory
2、 通过SqlSessionFactory创建SqlSession
3、 通过sqlsession执行数据库操作,事务提交,关闭。
mybatis缓存机制
1.一级缓存默认开启,基于本地hashMap的缓存,作用域是session,当session清空或者关闭的时候,缓存就会清空。
2.二级缓存,手动开启,作用域是Mapper,需要实现序列化接口。
分页插件实现
通过拦截待执行的SQL,重写SQL加上分页参数
Spring
spring 是一个轻量级的开发框架,提高开发人员的开发效率跟系统的可维护性。除了是框架之外,我认为他是个生态的基石。
通过spring帮我们创建对象bean,并且存储在容器中和维护bean的生命周期
使用Aop达到代码的可重用,声明式事务不需要我们来手动控制事务的提交等来达到简化开发。
IOC(控制反转)
之前我们创建对象的控制权在我们手里,现在使用IOC控制反转,将控制权交给Spring管理,使对象之间松耦合,也有利于功能的复用。
常见的注入:构造器注入,setter方法注入,注解注入
xml和注解的读取
DI(依赖注入)
是指在运行过程中将程序所需要的资源用Spring容器动态注入
AOP *
将一些公共的行为封装成一个可重用的模块,这个模块就叫做切面,AOP的动态代理不会去更改字节码,而是在每次运行过程中生成一个AOP对象,这个AOP对象就包含了目标对象的所有属性跟方法。
场景:如日志,事务管理,
实现:
JDK动态代理: 利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。(对象接口类)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,对于final类或方法,是无法继承的 (对象类)
AOP实现
//自定义注解 @Target(ElementType.METHOD) //定义注解的使用范围为方法 @Retention(RetentionPolicy.RUNTIME ) public @interface SaveHotKey { } //在对应想要使用的方法或者类上面加入以上注解 //切面 @Aspect @Component public class SaveHotKeyAspect { @Autowired private ElasticSearchUtils elasticSearchUtils; @Pointcut("@annotation(com.xxxx.cloud.elasticsearch.aop.SaveHotKey)") public void checkDataPoint(){ } @Before("checkDataPoint()") //前置通知 public void checkBefore(JoinPoint point){ Object[] args=point.getArgs(); ResourceQuery query= (ResourceQuery)args[0]; //存es的热搜词中 if (StringUtils.isNotBlank(query.getKeyWord())){ HotKeyWordsPo hotKeyWordsPo = new HotKeyWordsPo(); hotKeyWordsPo.setId(UUID.randomUUID().toString()); hotKeyWordsPo.setCreateTime(new Date()); hotKeyWordsPo.setSearchInput(query.getKeyWord()); try { elasticSearchUtils.addData(hotKeyWordsPo, ESConst.HOT_KEY_INDEX,hotKeyWordsPo.getId()); } catch (IOException e) { e.printStackTrace(); } } } /* @After("checkDataPoint()") //后置通知 public void checkAfter(){ }*/ }
1 @Aspect:把当前类标识为一个切面供容器读取
2.@Pointcut:aop切入点,表示在什么条件下触发
3.@annotation:声明以注解的方式来定义切点,注解为SaveHotKey的包路径
4.@Before:前置增强方法的标识,表示在标有注解的方法前执行切面方法
————————————————
版权声明:本文为CSDN博主「超多多和刘宝宝的代码世界」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_48329942/article/details/121016322
spring bean作用域
单例 原型 请求(request) 会话(session) 全局
BeanFactory和ApplicationContext有什么区别
BeanFactory在启动的时候不会去实例化Bean,从容器中拿Bean的时候才会去实例化
ApplicationContext:
是BeanFactory的子接口,扩展了其功能, 一般面向程序员身使用
ApplicationContext在启动的时候就把所有的Bean全部实例化了
Spring的对象默认是单例的还是多例的? 单例bean存不存在线程安全问题呢?(必会)
- 在spring中的对象默认是单例的,但是也可以配置为多例。
- 单例bean对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,多线程操作该bean对象时会出现线程安全问题。
原因是:多线程操作如果改变成员变量,其他线程无法访问该bean对象,造成数据混乱。
解决办法:在bean对象中避免定义可变成员变量;
在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。
Bean的生命周期
阶段一:bean的实例化和Di依赖注入
1.扫描xml文件,注解类,配置类中bean的定义
2.创建bean实例
3.注入bean依赖项(调用setting方法)
二阶段:检查Spring Awareness
1.实现了BeanNameAware接口,则调用setBeanName()方法
2.实现了 BeanClassLoaderAware接口,则调用setBeanClassLoader(...);
3. 实现了ApplicationContextAware接口,则调用setApplicationContext(...);
三阶段:创建bean生命周期回调
1.@PostConstruct注释,注释回调的方法上,1、2阶段Bean创建完毕即调用;
2. 实现InitializingBean接口,调用afterPropertiesSet(...),1、2阶段Bean创建完毕即调用;
- Bean定义中包含init-method(在XML中标签
的属性)或@Bean(initMethod="...")指定的方法,1、2阶段Bean创建完毕即调用;
四阶段:销毁bean生命周期回调
1. 实现DisposableBean接口,调用destroy(...),销毁Bean之前调用;
- Bean定义中包含destroy-method(在XML中标签
的属性)或@Bean(destroyMethod="...")指定的方法,销毁Bean之前调用;
Spring框架中都用到了哪些设计模式**
- 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例
- 单例模式:Bean默认为单例模式
- 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
- 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate
- 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener
- 适配器模式:
- 策略模式:加载资源文件的方式
- 装饰者模式
Spring的常用注解
@Component(组件) @Controller @Service @Repository(dao): 用于实例化对象
@Value: 简单属性的依赖注入
@Autowired: 对象属性的依赖注入
@Resource 按照属性名称依赖注入
@ComponentScan: 组件扫描
@PropertySource: 用于引入其它的properties配置文件
@Bean: 表在方法上,用于将方法的返回值对象放入容器
@Configuration: 被此注解标注的类,会被Spring认为是配置类。Spring在启动
@Import: 在一个配置类中导入其它配置类的内容
spring事务的实现原理
事务操作时AOP的核心体现,当一个方法添加@Transactional注解之后,spring会基于这个类生成一个代理对象,将这个代理对象作为bean,当使用到这个方法时,如果有事务处理,会把事物的自动提交给关闭,只有在执行逻辑没有发生异常时才会提交,否则就回滚。
spring事务什么时候会失效
1、bean对象没有交由spring容器管理
2、方法修饰符不是public
3、自身调用
4、数据库不支持事务
5、出现异常
Spring的事务传播行为
spring事务实现主要有两种方法:编程式 声明式,
spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。
备注(方便记忆): propagation传播
require必须的/suppor支持/mandatory 强制托管/requires-new 需要新建/ not -supported不支持/从不/nested嵌套的
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
SpringMVC
spring mvc是javaweb级别的一个轻量级框架,通过把Model,View,Controller。实现职责的解耦。
在我看来spring mvc把web开发分为两部分,一部分由框架帮我们完成,一部分由我们自己完成
执行流程
常用注解
@RequestMapping、@RequestBody、@ResponseBody、@PathVariable 、@RequestParam:
解决异常
创建一个自定义类实现异常接口,并实现异常处理方法
在自定义类和异常方法上加入注解。
SpringBoot
spring boot是spring的子项目,他去除了spring的复杂配置,节省开发时间。使用了约定大于配置的思想,让开发人员能够全身心的注重业务代码的开发。大大提高开发效率,减少开发周期。
版本锁定、起步依赖、内置Tomcat、自动配置
starter
starter是SpringBoot的启动器,他集成了web,mybatis,redis等技术的运行环境
在启动器启动的时候,回去扫描spring.factories的jar包文件,加载自动配置类,创建对象放入spring容器中
springboot执行main方法会发生什么?
SringApplication的类中已经做好了整合其他中间件如MyBatis,Redis的启动类。
启动spring容器:run方法传入的是当前类(主要是要传入SpringBootApplication的注解)和main函数的args参数,通过启动类的信息,创建spring容器。
启动tomcat运行项目
SpringbootApplication包含SpringBootConfiguration、EnableAutoConfiguration、componentScan和4个JDK原生注解。
springboot自动配置是怎么实现的
是由@EnableAutoConfiguration实现的,他内部主要是有@import导入了一个类,这个类中有一个方法会在项目启动时,去扫描spring.factories文件,跟根据自动配置类来创建对象,并放入到ioc容器中。
常用注解
@SpringBootApplication:它封装了核心的@SpringBootConfiguration +@EnableAutoConfiguration +@ComponentScan这三个类,大大节省了程序员配置时间,这就是SpringBoot的核心设计思想.
@MapperScan:spring-boot支持mybatis组件的一个注解,通过此注解指定mybatis接口类的路径,即可完成对mybatis接口的扫描
@RequestMapping,我们都需要明确请求的路径.
@GetMappping,@PostMapping, @PutMapping, @DeleteMapping
spring mvc和spring boot的区别
1、springMVC是Spring的一个模式,是一个Web框架,提供了一个轻度耦合的方式来开发Web应用;
2、SpringBoot是习惯优于配置,降低了项目搭建的难度;
3、springMVC需要使用到TomCat服务器,SpringBoot的话是内嵌了Tomcat服务器的;
Spring Cloud
微服务:单一职责、服务之间互相独立、互不干扰
分布式
限流和流量降级:对于流量高峰期的时候,限流的策略有可分为限制访问的绝对数量和控制流速,限流的算法有令牌桶算法。
灰度发布:是用于两个不同的版本同时在线上并行的情形,可以用于业务试错,也可以用于版本发布。一旦确认了新的版本就可以平滑的从旧版本切换到新的版本上。
使用需要解决的问题:
多版本的部署:分为客户端部署和服务端的部署两个方面,
流量的切分:入口流量,切分策略通常包括服务器权重,IP地址段或者用户标签来做流量的切分。
雪花算法(常见的限流算法)
总共长度为64bit
41bit时间戳:记录当前系统的具体时间,单位为毫秒。
10bit工作机器id:每台服务器有分配唯一id。
12bit序列号:
原因:对于传统的MySQL来说,当数据量过大时对其进行水平分表会导致多个表中会生成重复的id值。
解决:使用uuid作为主键,由于uuid时无序的字符串,对于增长主键这一定义不合适。
也可以使用redis的自增原子性来生成唯一id,但是这种用的少。
问题:依赖于的服务器的时间,服务器时钟回拨可能会生成重复id。
每次发生时钟回拨就将基础序列号加上指定的步长
第一次从0开始
第二次从1024开始
第三次从2048开始
幂等性
幂等性就是说对于同一操作或者多次请求的结果都是一致的。
解决幂等性的方案:
1.mysql/redis中设置业务id并设置为主键,且唯一。
2.使用redis或者zk的分布式锁
3.去重表使用适用于原先就有唯一的标识,如订单可以讲订单编号作为唯一标识存储在去重表中。并且放入事务中,如果重复创建数据库就会抛出唯一约束异常,操作回滚。
4.多版本控制(乐观锁思想)新增一个字段作为版本号的标识。