Apong's Blog

当你快坚持不住的时候,困难也快坚持不住了

0%

每日杂记 day4

。。昨天被几道算法题弄的迷失了方向


八股

Spring

IOC

控制反转,将创建、管理对象的权力交给第三方容器,在开发时只需要注入对象就可以直接使用,不需要关心复杂的依赖关系。

Component 和 Bean 注解的区别

Component 作用于类,通过 ComponentScan 指明路径可以将标注的类转化为 Spring 管理的 Bean。

Bean 作用于方法,将方法的返回值作为一个 Spring Bean,生效的前提是所在的类被声明为了 bean,如 Configuration;

Bean 比 Component 的自定义性能力强,比如再需要引入第三方库的依赖时,可以声明一个 Bean 标注的方法来实现。

如何获得 Bean

  1. 通过 Spring 容器上下文来手动获取 bean
  2. 通过注解的方式来自动注入 bean
    1. Autowired
    2. Resource
    3. Inject

autowired 和 resource 的区别

前者是 Spring 提供的注解,后者是 jdk 提供的。

前者通过类型获取 bean,如果同一个类型有多个实现类会会按照名称来获取。这时候可以借助 Qualified 注解声明需要注入类的名称。

后者默认通过名称获取 bean,如果无法匹配就会根据类型的方式来获取。

如果也有多个实现类呢?

那 resource 就要结合名称来获取了。

Resource注解有两个属性分别是 name,type。

指定哪一个,默认获取方式就是哪一个。

如果都指定,就结合两个属性进行获取。

:question: autowired还支持在构造函数上在使用?Resource 只支持在字段和方法上。

Bean 的作用域有哪些?

主要有:

  • singleton,单例模式
  • prototype,每次获取的都是不同的实例
  • request:每次 HTTP 请求都会产生一个 bean,只有在 web 应用中可以用。
  • session,类似request

如何配置

通过 @Scope 注解

Bean 是线程安全的吗?

在单例模式下,bean 线程不安全,如果它是有状态的,多线程修改会存在资源竞争问题。

Bean 的生命周期

实例化 -> 属性赋值 -> 初始化 -> 销毁

img

AOP

面向切面编程,是一个对横切关注点的增强,抽象出公共业务,降低不同模块间的耦合度。

实现原理就是动态代理,如果要代理的对象实现了接口就使用 jdk 的 proxy 创建代理,没有接口就用第三方库 cglib 进行动态代理。

jdk proxy 和 cglib 的区别?

JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。

就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显

和 OOP 的区别:

oop 是封装为对象,实现代码的模块化和层次化。

Spring aop 和 aspectj aop 的区别

前者是运行时增强,后者是编译期增强,将增强的代码写入字节码中,效率更高。

aop 的通知类型有哪些?

  1. before 方法执行前

  2. after 方法执行后

  3. afterReturning 方法返回结果后

  4. afterThrowing 方法抛出异常后

  5. around 编程式的控制目标对象的调用,可以直接拿到目标对象和要执行的方法。

多个切面如何控制执行顺序

通过 @Order 注解,值越小优先级越高

aop 应用场景

  1. 日志记录
  2. 事务管理
  3. 权限控制
  4. 接口限流等

Spring MVC

将业务逻辑、数据、界面分离来组织代码

核心组件:

DispatcherServlet:核心处理器,复杂接受请求、分发、给予客户端响应。

HandlerMapping:根据 Url 匹配查找能处理的 Handler,并且将拦截器和 Handler 一起封装。

HandlerAdapter:根据 handlermapping 找到的Handler,去适配执行对应的Handler

Handler:实际处理的处理器

ViewResovler:视图解析器,根据 Handler 返回的逻辑视图,解析渲染界面,并传递给 dispatcherservlet 响应给客户端。

img

如果有多个拦截了异常类(或父类)的统一异常处理通知,会都执行吗?

首先会根据拦截异常类型,添加所有符合类型(包括父类)异常处理,最后根据匹配程度选取优先级最高的 1 个。

Spring 的三级缓存

一级缓存:存放最终创建完成的 bean

二级缓存:存放刚刚实例化后的 bean 或 代理对象。

三级缓存,存放对象工厂,可以生成原始 Bean 或代理对象,只对单例 bean 生效,多例直接生成新的即可。

获取顺序:一级 -> 二级 -> 三级

Spring 事务

编程式事务,通过 TransactionTemplate 或 TransactionManager 手动管理事务。

声明式事务,基于 @Transactional 注解通过 aop 实现事务。

TransactionManager 使用

  1. 注入 PlatformTransactionManager。
  2. 定义事务信息 TransactionDefinition
  3. 得到事务运行状态 TransactionStatus
  4. 修改状态
    1. commit
    2. rollback

事务的传播行为

  1. RRQUIRED 加入事务,没有则新建,是默认的行为
  2. REQUIRES_NEW 新建事务
  3. REQUIRED_NESTED 嵌套事务
  4. MANDATORY 强制事务,没有则抛出异常

新建事务外部回滚不会影响内部新建的事务,但是如果内存回滚并抛出了相应异常,外部也会回滚,因为会捕捉到异常。

嵌套事务如果外部回滚,其也会回滚;反之不会。

事务的隔离

主要分为

  1. READ_COMMITED 只能读取事务提交后的值。
  2. REPETABLE_READ 允许重复读。

@Transaction 默认回滚策略

runtimeException ,而checked exception 不会回滚

只读事务

一组查询语句应该声明为只读事务。

MySQL 默认对每一个新建立的连接都启用了autocommit模式

MySQL 内部每一条 sql 语句都会新建一个事务,相互之间是独立的,执行时间不同就有可能同个值读取不一致问题,造成读取逻辑错乱。

同时声明为只读事务,还可以优化性能。

事务的 ACID 特性

A:原子性,C:一致性,I:隔离性,D:持久性

A, I, D -> C

算法题

最大子数组和

普通解法:

遍历两两区间,通过 sum 记录所有子数组,并保留 max。

动态规划解法:

将问题转化为 n 个“无后效性”问题:即前一个问题的结果与后一个问题无关。

再找到“状态方程”的变换条件:由于连续,后一个问题的最大子数组和一定是基于前一个问题的和。

  • 小于 0 直接“中断”,sum 从头算起。
  • 大于 0 继续计算。

最后遍历完所有问题,得到最终结果 max。

合并区间

将能够相接的区间合并在一起:相接即区间有重合部分。

关键在于排序,因为能够合并的区间,一定在相邻位置。

双指针建立左右边界,同时需要记录最大右边界。

移动条件:只要区间 x 的左边界<=就表示有重合部分,右边界继续扩张;否则重新记录左边界。

最后返回所有的区间结果。