目录
被问到的面试题
一、
Spring
jdk的动态代理和cglib的动态代理的区别
-
jdk的动态代理(基于接口实现)
-
实现InvocationHandler接口重写里面的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
-
Method类中的invoke方法
Object result = method.invoke(rent, args); //method:代表的就是Rent接口中的rent方法 //rent:接口对象 //args:可以指定rent方法中的参数值
-
返回对象
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); //注意:rent代表的就是接口实例(因此jdk动态代理是基于接口实现的)
package com.my.demo03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //使用这个类,来自动生成代理类 public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Rent rent; public void setRent(Rent rent) { this.rent = rent; } // Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), // new Class<?>[] { Foo.class }, // handler); //定义一个getProxy方法:该方法用来创建代理类和实例 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); } //处理代理类,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); Object result = method.invoke(rent, args); payMoney(); return result; } public void seeHouse(){ System.out.println("中介带我们看房子!"); } public void payMoney(){ System.out.println("客户支付房租定金!"); } }
-
jdk动态代理是基于接口实现的,cglib动态代理是基于class类实现的
-
JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架(用来操控字节码的)写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低
-
JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高
-
spring中的aop用的是什么代理模式
- 默认情况下使用的是jdk的动态代理
- 一些情况下使用的是cglib的动态代理(比如没有指定代理接口)
事务的回滚
- 就是即时有时候你给一些业务方法开启了事务支持(不管是编程式还是声明式),在一些特殊异常情况下事务是不会回滚的
事务的传播行为
- 事务协调员:就是单个的业务方法
- 事务管理员:简单来说就是开启事务支持的业务方法(保证原子性)
- 举例:比如转账业务,a给b转账,a账户减钱b账户加钱,同时转账介绍打印日志,要求无论转账是否成功,打印日志方法必须执行
spring事务失效的场景有哪些
- 使用
@Transactional
注解修饰的业务方法抛出的异常不是spring的事务支持的异常,需要使用注解的rollbackFor
属性来指定 - 开启事务支持的方法修饰符非public
- 数据表本身不支持事务
@Transactional
注解所在的类没有被spring管理- catch异常但是没有throw,捕获了异常但是没有抛出
- 数据源没有配置事务管理器
- 传播类型不支持事务
- 多线程调用导致事务失效
spring的生命周期和作用域
- 作用域:
- singleton:单例bean
- prototype:原型模式
- request:每次请求都会创建新的bean对象
- session:同一Session会话
- application:全局整个web应用
- 生命周期:普通对象–依赖注入–初始化–放入单例池–bean对象
spring的自动装配方式有哪些
- byType
- byName
- 通过当前类的“对应参数”的构造器注入
public class RefreshTokenInterceptor implements HandlerInterceptor {
//注意:LoginInterceptor类没有被Spring Boot管理,所以不能使用SpringBoot的自动装配功能
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
}
spring的aop应用场景有哪些
简单介绍一下SpringIOC和AOP
- AOP:面向切面编程,是一种设计规范,它的作用就是在不改动原始设计的基础上为对应的功能进行增强,这也正如Spring的理念就是非入侵式的
- 怎么实现面向切面编程:对于我们业务中的执行方法我们叫“连接点”,而我们要插入的公共方法叫“通知”(所属通知类),要往哪些执行方法插入通知需要指定位置我们叫“切点”(不止匹配一个执行方法),而通知和切点怎么联系?是通过“切面”来指定
- AOP的工作流程:启动容器,读取切面中已经配置的切点 ,在判断bean对象所对应的类中的方法是否匹配到切面配置的切点
spring中的bean是线程安全的吗
- 其实在spring框架中,并没有提供bean的线程安全策略,所以,spring容器中的bean并不具备线程安全的特性
- prototype(多例bean):对于prototype中作用域中的bean,因为每次getBean的时候,都会创建一个新的对象,线程之间不存在Bean共享问题,因此prototype作用域下的bean不存在线程安全问题
- singleton(单例bean):对于singleton作用域中的bean,所有的线程都是共享一个单例实例的bean,因此是存在线程安全问题的,但是如果单例bean是一个无状态的bean,即多线程操作中不会对bean的成员变量进行查询以外的操作(不存在多个线程同时写这个成员变量的场景),那么这个单例bean就是线程安全的
数据库创建索引
-
索引分类
- 单列索引(普通索引、唯一索引、主键索引)
- 组合索引
-
普通索引
create index 索引名称 on 表名(字段名) alter table 表名 add index 索引名称(字段名)
-
唯一索引
create unique index 索引名称 on 表名(字段名) alter table 表名 add unique (字段名)
-
主键索引:唯一索引和主键索引的区别就是主键索引不能为空值
-
组合索引
create index 索引名称 on 表名(字段1,字段2,...)
注意:创建一个组合索引,本质上创建了多个索引,最左匹配原则
-
删除索引
dorp index 索引名称 on 表名
索引的优点
- 唯一索引和主键索引能够保证每行数据的唯一性
- 建立索引可以大大提高检索数据的效率
- 在查询中使用索引可以提高性能
- 联表查询加速变得连接
- 在分组和排序中减少查询时间
索引的缺点
- 创建索引和维护比较耗时,会随着数据量的增加而增加
- 索引文件会占用物理空间
什么情况下不创建索引
- 数据比较少
- 对表中数据的修改操作比查询操作次数更频繁
数据库的存储过程
索引和存储过程的应用场景
二、
怎么理解数据双向绑定
- Vue的数据双向绑定指的是model层和view层的数据双向绑定,只要一层发生改变另一层也会随之改变
怎么理解MVVM模型
- view视图层:前端html结构
- model数据层:从服务端获取的数据,将这些数据根据某种方式渲染到页面上
- viewmodel业务逻辑的执行者:将视图层和数据层关联起来,进行数据的动态更新