美文网首页
葵花宝典-java面试题

葵花宝典-java面试题

作者: KICHUN | 来源:发表于2018-12-25 17:16 被阅读0次

    ioc控制反转

    面向对象的一种设计原则
    spring的核心之一
    将创建和管理对象交由容器去做,不显式的new对象
    

    接口设计

    restful接口设计:安全性,通常为token拦截,接口签名
    基于接口编程
        将业务方法抽象成接口,具体实现由实现类去做
        需求变化时只需修改实现类
        对拓展开发,对修改闭合
    

    https

    • 超文本传输安全协议,加入SSL协议,SSL依靠证书来验证服务端身份合法性,并为数据进行加密(密文传输)。整个传输过程中使用了对称加密和非对称加密
      步骤:
      第一次请求:客户端发起请求-服务端443端口-返回公钥和证书信息-客户端验证证书合法性-生成私钥使用公钥进行加密
      第二次请求:使用客户端私钥进行对称加密数据+非对称私钥请求服务端-服务端使用私钥解密客户端私钥,使用客户端明文私钥对称解密数据
      CA信任A,B信任CA,B信任A
      web服务器均支持,下载证书到服务器指定目录并做相关配置即可

    mysql和mongo对比

    mysql
        成熟的关系型数据库,非常稳定且应用广泛
        支持数据库事务,支持多表的join操作
    mongodb
        非常火的nosql数据库,不够稳定
        不支持事务,不支持join
        支持类似sql的查询语句,可以轻易查询内嵌对象
        数据格式松散而灵活
        适合大数据量的存储和查询,适用于日志、内容管理等应用
        官方支持的拓展分片,轻易扩容
        虚拟内存+持久化,热点数据在内存中,对内存要求比较高
    

    字符集

    • html中meta标签字符集作用:告知浏览器该页面的字符集,浏览器将使用该字符集做解析
    • MySQL连接字符串中指定字符集的作用:告知数据库当前客户端连接使用的字符集。MySQL将以客户端连接字符集-连接字符集-数据库-表-字段字符集进行顺序处理
    • URL中的iso8859-1

    spring中bean的生命周期

    • 1.实现InitalizingBean和DisposableBean。分别在对象属性设置后执行afterProperitesSet()和destory()方法。不建议,与spring框架耦合
    • 2.在配置文件中配置init-method和destory-method方法,或者使用@PostConstruct及@PreDestory注解
    • 3.实现BeanPostProcessor。 该接口中包含两个方法, postProcessBeforeInitialization和postProcessAfterInitialization。
      postProcessBeforeInitialization方法会在容器中的Bean初始化之前执行, postProcessAfterInitialization方法在容器中的Bean初始化之后执行。

    如何在bean中使用spring的对象

    继承*Aware接口  
    ApplicationContextAware: 获得ApplicationContext对象,可以用来获取所有Bean definition的名字。
    BeanFactoryAware:获得BeanFactory对象,可以用来检测Bean的作用域。
    BeanNameAware:获得Bean在配置文件中定义的名字。
    ResourceLoaderAware:获得ResourceLoader对象,可以获得classpath中某个文件。
    ServletContextAware:在一个MVC应用中可以获取ServletContext对象,可以读取context中的参数。
    ServletConfigAware: 在一个MVC应用中可以获取ServletConfig对象,可以读取config中的参数。
    

    springmvc执行流程

    dispatcherServlet(核心)拦截请求,dispatcherServlet请求HandlerMappiing查找并映射到处理器,由处理器适配器调用匹配的controller并返回modelAndView,最后由视图解析器对视图进行解析

    springSecurity

    由spring提供的鉴权框架,核心为用户认证及用户授权两个部分
    web.xml中配置DelegatingFilterProxy授权过滤器
    编写security.xml文件,引入springSecurity命名空间
    配置无需鉴权的URL,配置认证过滤器,配置授权过滤器
    认证过滤器继承UsernamePasswordAuthenticationFilter
        注入认证结果处理器,需实现AccessDeniedHandler,AuthenticationFailureHandler,AuthenticationSuccessHandler,重写相关方法(认证异常处理封装,页面跳转等)
        注入AuthenticationManager 
            注入AuthenticationProvider(可以有多个)
                注入自定义provider,该provider需要实现AuthenticationProvider接口,重写authenticate()方法,该方法内对用户名密码进行校验。并抛出认证异常或返回UsernamePasswordAuthenticationToken
    
    授权过滤器继承FilterSecurityInterceptor
        注入AccessDecisionManager,实现AccessDecisionManager接口的decide()方法,该方法中判断当前用户是否有该URL访问权限
        注入AuthenticationManager认证管理器
        注入FilterInvocationSecurityMetadataSource,实现FilterInvocationSecurityMetadataSource接口,缓存所有菜单权限
    注入认证国际化文件位置
    注入登出LogoutSuccessHandler,实现LogoutSuccessHandler接口中onLogoutSuccess()方法,禁用session
    其他重要类SecurityContextHolder,可以获取当前登录Authentication对象
    

    shiro

    引入shiro相关依赖
    创建ShiroConfig配置类,标识@Configuration
    注入ShiroFilterFactoryBean类
        注入filterChainDefinitionMap属性,设置无需拦截的URL
        设置登录、登录成功跳转、权限不足的跳转URL
        注入securityManager属性,安全管理器为shiro框架的核心,认证和授权操作在该类的Realm中进行
            注入Realm类,该类需继承AuthorizingRealm,并重新doGetAuthorizationInfo()及doGetAuthenticationInfo()方法,分别进行认证和授权
            注入CacheManager等
    

    springaop原理

    通过代理实现。有jdk的动态代理和cglib的代理。具体使用哪种方式是看策略决定,默认的策略是如果目标切面类是接口则用jdk的动态代理其他用cglib的代理。

    spring的bean作用域

    singleton单例,spring容器默认
    prototype,多例,每次getBean进行new,然后容器不再对对象实例进行管理
    以下仅在webApplicationContext中适用
    request,一次请求
    session,一个会话
    globalsession,全局会话中
    

    springboot数据源配置

    使用@Configuration标识配置类
    使用@Bean注入返回的DataSource
    使用@ConfigurationProterties注入数据properties前缀
    使用@Primary标识这是一个默认主配置
    使用DataSourceBuilder建造一个指定类型的数据源
    

    jdk动态代理及其实现方式

    InvocationHandler是JDK动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法

    实现方式:

    1、获取代理类要实现的接口
    2、检查上面得到的接口中有没有定义 equals或者hashcode的接口
    3、调用Proxy.newProxyInstance创建代理对象
    

    项目权限实现方式

    五表+security(或shiro)或者自定义权限
    

    前后分离难点

    原有权限框架移除
    对token的管理
    

    sso怎么实现

    通过共享Session,用户登陆时对用户名密码进行验证,通过后在客户端有cookie储存token凭证,在访问其他站点的时候由cookie发送token凭证进行验证是否登陆
    

    mybatis怎么配置一对多

    在resultmap标签中使用collection标签
    column传入主表参数一般为id然后用select参数传入查询id
    select标签写查询语句
    

    spring事务的原理

    Spring事务 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的
    

    事务隔离级别有哪些,分别会有什么问题

    隔离级别 隔离级别的值 导致的问题
    读未提交 0 导致脏读
    读已提交 1 避免脏读,允许不可重复读和幻读
    可重复读 2 避免脏读,不可重复读,允许幻读
    可串行化 3 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,

    • 脏读:
      一事务对数据进行了增删改,但未提交,另一事务可以读取到未提交的数据。如果第一个事务这时候回滚了,那么第二个事务就读到了脏数据。

    • 不可重复读:
      一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改,这时候两次读取的数据是不一致的。

    • 幻读:
      第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围增加一条数据,这时候第一个事务就会丢失对新增数据的修改。

    mysql默认使用什么隔离级别

    mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读,oracle默认是READ COMMITTED,也就是读已提交
    

    sql怎么优化

    索引
    explain

    如何分析一个系统的性能

    看qps(每秒查询率)。Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。
    当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
    

    配置nginx实现集群服务和负载均衡

    1、下载nginx
    2、配置upstream和server和listen(端口)
    3、使用轮询策略(默认轮询,加权轮询,哈希轮询)
    

    提升qps:

    集群+负载均衡
    增加缓存
    系统拆分
    分库分表、数据库读写分离
    垂直拆分+水平拆分
    异步化+MQ
    

    java 多线程包之锁

    1:减少锁持有时间
    例如:对一个方法加锁,不如对方法中需要同步的几行代码加锁;

    2:减小锁粒度
    例如:ConcurrentHashMap采取对segment加锁而不是整个map加锁,提高并发性;(即锁分段技术,每次只锁一个桶,而不是整个table)
    在存储结构中ConcurrentHashMap比HashMap多出了一个类Segment,而Segment是一个可重入锁
    java8接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用synchronized 和 CAS 来操作。只同步锁定当前链表和红黑树首节点,hash不冲突即无并发问题
    3:锁分离
    根据同步操作的性质,把锁划分为的读锁和写锁,读锁之间不互斥,提高了并发性。

    4:锁粗化
    这看起来与思路1有冲突,其实不然。思路1是针对一个线程中只有个别地方需要同步,所以把锁加在同步的语句上而不是更大的范围,减少线程持有锁的时间;
    而锁粗化是指:在一个间隔性地需要执行同步语句的线程中,如果在不连续的同步块间频繁加锁解锁是很耗性能的,因此把加锁范围扩大,把这些不连续的同步语句进行一次性加锁解锁。虽然线程持有锁的时间增加了,但是总体来说是优化了的。

    5:锁消除
    锁消除是编译器做的事:根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程(即不会影响线程空间外的数据),那么可以认为这段代码是线程安全的,不必要加锁。

    安全类型原子类型

    Atomic开头的类,在 java.util.concurrent.atomic包下
    原子类型主要使用CAS compare and swap比较和交换 + volaite + native本地方法来保证原子性
    避免了synchronized的高开销,提升效率
    

    mysql的锁表问题

    SHOW PROCESSLIST
    kill id   //杀掉被锁的表
    

    java内存模型

    线程堆、栈、常量池、静态池

    堆内存空间
    一般来说是虚拟机管理最大的内存空间,堆内存被所有线程共享,主要存放对象实例。是GC的主要区域,细分为新生代,老年代,永久代。分代是为了更好更快地回收内存
    栈空间
    线程私有,先进后出

    jvm垃圾回收算法

    (1).标记-清除算法:
    最基础的垃圾收集算法,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成之后统一回收掉所有被标记的对象。
    标记-清除算法的缺点有两个:首先,效率问题,标记和清除效率都不高。其次,标记清除之后会产生大量的不连续的内存碎片,空间碎片太多会导致当程序需要为较大对象分配内存时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

    (2).复制算法:
    将可用内存按容量分成大小相等的两块,每次只使用其中一块,当这块内存使用完了,就将还存活的对象复制到另一块内存上去,然后把使用过的内存空间一次清理掉。这样使得每次都是对其中一块内存进行回收,内存分配时不用考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
    复制算法的缺点显而易见,可使用的内存降为原来一半。

    (3).标记-整理算法:
    标记-整理算法在标记-清除算法基础上做了改进,标记阶段是相同的标记出所有需要回收的对象,在标记完成之后不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,在移动过程中清理掉可回收的对象,这个过程叫做整理。
    标记-整理算法相比标记-清除算法的优点是内存被整理以后不会产生大量不连续内存碎片问题。
    复制算法在对象存活率高的情况下就要执行较多的复制操作,效率将会变低,而在对象存活率高的情况下使用标记-整理算法效率会大大提高。

    (4).分代收集算法:
    根据内存中对象的存活周期不同,将内存划分为几块,java的虚拟机中一般把内存划分为新生代和年老代,当新创建对象时一般在新生代中分配内存空间,当新生代垃圾收集器回收几次之后仍然存活的对象会被移动到年老代内存中,当大对象在新生代中无法找到足够的连续内存时也直接在年老代中创建。

    如何排查内存泄漏

    1. jstat -gcutil 看jvm内存占用,如果存在问题用轻量级的jmap看存活对象的元素和占用内存空间,找到对象类型,写btrach脚本 btrace - cp  bulid  看堆栈信息找到具体的代码位置
    2. 使用jmap命令进行dump
    3. 通过增加了参数 -XX:+HeapDumpOnOutOfMemoryError 和 -XX:HeapDumpPath 当在 OOM 的时候,服务会生成一个 java_pid$pid.hprof 二进制文件。使用相关工具(jconsole,MAT)对dump文件进行分析
    4.使用jstack -l pid 对线程进行dump     
    

    如何排查cpu 占用过高?

    1. 使用top -c 命令查看占用进程ID
    2. 使用top -Hp pid 查看一个进程的线程运行信息列表
    3. 使用printf "%x\n" 线程ID得到十六进制   线程ID
    4. 使用 jstack 进程ID| grep 线程十六进制ID -C5 --color获取线程堆栈信息
    

    搜索引擎

    ElasticcSesarch
    建立在全文搜索引擎Apache Lucene(TM)基础上的搜索引擎
    

    rpc原理

    Remote Procedure Call 远程过程调用
    简单的说,RPC就是从一台机器(客户端)上通过参数传递的方式网络调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果

    软负载均衡怎么去做

    软件负载均衡一般通过两种方式来实现:基于操作系统的软负载实现和基于第三方应用的软负载实现
    LVS就是基于Linux操作系统实现的一种软负载,HA Proxy就是基于第三应用实现的软负载。

    dubbo的软负载均衡如何实现的

    在集群负载均衡时,Dubbo提供了多种均衡策略
    Random LoadBalance
    默认随机
    RoundRobin LoadBalance
    轮循
    LeastActive LoadBalance
    最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
    使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
    ConsistentHash LoadBalance
    哈希轮询

    cas是什么

    比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令。 
    它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。 
    这是作为单个原子操作完成的。 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。
    操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成
    

    cas原理是什么

    现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 CAS 就用这些代替了锁定。使用volatile语句让线程之间的数据共享
    

    CAS和ABA问题

    原值被修改过,但比较相同导致提交成功。解决方式:增加一个版本号,值和版本号一致才能修改成功
    

    volatile:线程可见(强制刷新到主内存),禁止指令重排

    原子性
    可见性
    有序性
    

    AQS

    AQS的全称为(AbstractQueuedSynchronizer),这个类在java.util.concurrent.locks包下面
    AQS是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,
    比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。当然,我们自己也能利用AQS非常轻松容易地构造出符合我们自己需求的同步器
    

    AQS原理

    核心思想:当资源闲置时将当前线程设为工作线程,并锁定资源
    当资源锁定时,将当前线程阻塞并加入CLH队列,CLH队列锁实现了阻塞唤醒机制
    

    AQS定义两种资源共享方式

    Exclusive 独占:只允许一个线程访问,例如ReetrantLock。又分为公平锁和非公平锁
    Share 共享:允许多个线程进行访问,例如CountDownLatch、CyclicBarrier
    

    AQS 组件总结

    • Semaphore(信号量)-允许多个线程同时访问: synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。
    • CountDownLatch (倒计时器): CountDownLatch是一个同步工具类,用来协调多个线程之间的同步。这 个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。
    • CyclicBarrier(循环栅栏): CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。
      CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
      CyclicBarrier默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。

    ReentrantLock实现原理

    基于AQS实现,aqs中Unsafe是jdk提供的硬件级别的原子操作,原理是CAS
    

    什么是线程局部变量?

    • 是Thread变量,每次new ThreadLocal()时实际为获取当前线程的ThreadLocalMap
    • 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,是线程隔离的。
    • 线程隔离的秘密在于ThreadLocalMap类(ThreadLocal的静态内部类)线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。
    • Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式
    • 但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。
    • ThreadLocal的方法:void set(T value)、T get()以及T initialValue()

    分布式事务

    原因:多个服务节点、多个资源节点
    一次完整的操作使用了不同节点的服务和操作了不同节点的资源
    

    使用分布式事务的原则:

    能不用就不用
    根据业务需求,判断是否需要强一致性
    

    常用分布式事务解决方案

    简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性

    • XA协议
      jtom/atomikos(强一致性),两阶段提交,预提交阶段,事务管理器根据要求每个数据库提交数据。优点:强一致。缺点:单点问题,同步阻塞问题,数据不一致问题
      XA 协议比较简单,成本较低,但是其单点问题,以及不能支持高并发(由于同步阻塞)依然是其最大的弱点。
    • tcc方案,Try-Confirm-Cancel 举例:库存扣减(强一致性)
      TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。
      主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。

    tcc模式特点
    该模式对代码的嵌入性高,要求每个业务需要写三种步骤的操作。
    该模式对有无本地事务控制都可以支持使用面广。
    数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。

    基于本地消息实现分布式事务,在消费方也需要有一张消息消费表记录验证消息有消息,(支付宝有此应用)(最终一致性)
    阿里GTS,基本了解和lcn原理一样,实现方式不同
    LCN
    支持dubbo和springcloud等rpc框架
    local confirm notify
    基于本地事务 对连接池进行代理(假关闭),
    事务发起方及参与的Service方法加入@LcnTransaction 分布式事务注解,事务发起方创建事务组获取GroupId
    业务参与方加入事务组
    事务发起方通知事务组
    通知事务单元
    响应事务发起方

    • lcn模式特点
      该模式对代码的嵌入性为低。
      该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。
      该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。
      该模式缺陷在于代理的连接需要随事务发起方一共释放连接,增加了连接占用的时间。

    lcn如何通知事务提交
    客户端方法执行完毕后对连接进行假关闭,通过netty长连接与事务管理器保持心跳,事务管理器通知客户端后,唤醒相应的进程,然后在本地事务Connection切面中根据这些信息进行提交或回滚

    lcn对dubbo的拓展支持
    调用拦截拓展(生产和消费者各一个Filter)
    负载均衡拓展(四个loadBlance,分别为Random随机、轮询RoundRobin、最小活跃LeastActive,一致性哈希ConsistentHash)

    执行业务后添加到事务组,最终通知关闭事务组,提交。中途出现异常则进行回滚

    • Restful接口签名
      生成appId和私钥secret
      请求参数加入时间戳及APPID使用URL格式拼串
      对参数进行非对称加密生成sign签名
      将参数、APPID、时间戳、sign进行签名,请求

    • 设计模式六大原则

    1. 开闭原则 Open Close Principle
      即对拓展开放,对修改闭合

    2. 里氏代换原则 liskov Substitution Principle
      里氏代换原则:面向对象设计的基本原则之一,任何基类可以出现的地方,子类一定可以出现,是开闭原则的补充

    3. 依赖倒转原则 Dependence Inversion Principle
      即面向接口编程,依赖抽象不依赖具体

    4. 接口隔离原则 Interface Segregation Principle
      使用多个隔离的接口比使用单个接口好,降低耦合

    5. 迪米特法则(最少知道原则)Demeter Principle
      一个实体应当尽量少与其他实体间发生相互作用,使系统功能相对独立

    6. 合成复用原则 Composite Reuse Principle
      尽量使用合成/聚合的方式,而不是使用继承

    redis 速度快的原因

    基于内存的操作
    数据结构简单,数据操作简单
    单线程,减少线程切换、竞争等开销、不存在锁问题。为什么单线程?单线程容易实现,cpu不是速度的瓶颈
    使用多路io复用模型(多个网络连接复用一个线程,即单线程处理多个请求)
    
    • 支付接口
      统一下单接口(预支付接口),获取支付所需参数(加签)
      客户端根据统一下单接口返回参数向平台发起支付
      平台回调商户回调接口,做订单完成业务(验签)

    JVM与性能优化

    描述一下 JVM 加载 Class 文件的原理机制?

    • 装载方式: 
      1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中,
      2.显式装载, 通过class.forname()等方法,显式加载需要的类
    Bootstrap Loader  // 负责加载系统类 (指的是内置类,像是String,对应于C#中的System类和C/C++标准库中的类)
                | 
              - - ExtClassLoader   // 负责加载扩展类(就是继承类和实现类)
                              | 
                          - - AppClassLoader   // 负责加载应用类(程序员自定义的类)
    
    • 装载(查找导入class)--连接(检查class准备静态成员空间)--初始化(静态变量静态代码块)

    什么是类加载器?

    将class文件加载到内存,并进行校验解析初始化形成jvm可以直接使用的java类
    

    类加载器有哪些?

    三种 引导类加载器,拓展类加载器,应用类加载器
    

    什么是tomcat类加载机制?

    类加载器双亲委派模型机制?

    某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载

    Java 内存分配?

    JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method,也叫静态区):
    
    • 堆区:
      1.存储的全部是对象,每个对象都包含一个与之对应的class的信息(class的目的是得到操作指令) ;
      2.jvm只有一个堆区(heap),且被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身和数组本身;

    • 栈区:
      1.每个线程包含一个栈区,栈中只保存基础数据类型本身和自定义对象的引用;
      2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问;
      3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令);

    • 方法区(静态区):
      1.被所有的线程共享,方法区包含所有的class(class是指类的原始代码,要创建一个类的对象,首先要把该类的代码加载到方法区中,并且初始化)和static变量。
      2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

    Java 中会存在内存泄漏吗,简述一下?

    理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题
    然而在实际开发中,可能会存在无用但可达(被引用)的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生
    

    什么是GC? 为什么要有 GC?

    垃圾回收,将释放内存的操作交由jvm来做,防止因代码遗漏疏忽造成的内存泄漏
    

    简述一下Java 垃圾回收机制?

    如何判断一个对象是否存活?
    在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的。
    这个算法的基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),
    当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的

    深拷贝和浅拷贝?

    浅拷贝:只拷贝基本数据类型,引用类型只拷贝引用
    深拷贝:对应用类型成员进行拷贝,重写Object的clone方法
    

    常用的性能优化方式有哪些?

    代码优化==不合理代码,比如循环,重复判断及操作
    数据库优化==索引,sql调优
    架构调优==缓存,连接池,集群,异步,jvm调优
    

    说说分布式缓存和一致性哈希?

    一致性哈希

    一致性哈希可以有效地解决分布式存储结构下动态增加和删除节点所带来的问题
    哈希环,将环形数据结构分成固定大小的槽,每个key哈希后可以落在一个对应的位置,顺时针第一个即是该服务节点

    Redis

    redis数据结构有哪些?

    string list set zset hash
    

    Redis缓存穿透,缓存雪崩?

    • 缓存雪崩:加锁排队(会导致超时等待),缓存过期标记(判断缓存是否过期,过期则异步更新缓存在更新标记)
    • 缓存穿透:
      有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
      缓存和数据库中都没有数据,使用空缓存
    • 缓存预热:即缓存加载,常见方式有页面触发、启动监听加载、定时刷新

    如何使用Redis来实现分布式锁?

    使用set if not exiest对key上锁并返回唯一解锁标识,利用redis单线程的特点保证加锁解锁安全
    

    Redis的并发竞争问题(先读再写)如何解决?

    利用redis自带的incr和incrby命令
    利用redis的watch命令
    其他自定义锁
    

    Redis持久化的几种方式,优缺点是什么,怎么实现的?

    RDB持久化,定时将内存中的数据dump到磁盘,快,丢失数据多
    AOP持久化,以日志的方式记录写删操作,慢,大,丢失少
    

    Redis的缓存失效策略?

    缓存不足时,淘汰哪些缓存?移除最少使用、随机删除、移除过期时间短等策略
    

    Redis集群,高可用,原理?

    key哈希取余存储到对应哈希槽
    节点互通,半数投票不可达认为fail宕机
    

    Redis缓存分片?

    拓展容量,提高可用性
    

    redis队列应用场景?

     通过消息队列的先进先出(FIFO)的特点结合Redis的list中的push和pop操作
    

    三、网络编程

    HTTP协议的交互流程• HTTP和HTTPS的差异,SSL的交互流程?

    https是在http协议基础上增加了使用SSL加密传送信息的协议
    https需要申请ca证书
    http端口80 https端口是443
    

    TCP的滑动窗口协议有什么用?

    该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。可以探寻当前网络合适发送分组数量,提高速度

    HTTP协议都有哪些方法?

    有8中,常用的有GET POST PUT DELETE 
    

    Socket交互的基本流程?

    发送带header的http请求
    服务器响应使用的协议
    建立连接

    讲讲tcp协议(建连过程,慢启动,滑动窗口,七层模型)?

    三次握手、四层模型、七层模型、安全的  
    

    webservice协议(wsdl/soap格式,与rest协议的区别)?

    SOAP协议 = HTTP协议 + XML数据格式
    WSDL(Web Services Description Language)就是这样一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。
    

    说说Netty线程模型,什么是零拷贝?

    netty零拷贝。传统拷贝:系统内存到用户内存的拷贝
    零拷贝:通过减少用户态和系统态的切换,减少缓存区间的复制次数来提高拷贝速度
    

    DNS解析过程?

    访问一个域名,会向域名服务器查询IP地址,根据返回的IP进行访问
    

    TCP如何保证数据的可靠传输的?

    面向连接的,可靠的。需要校验和应答。丢包超时重发
    

    四、设计模式与重构

    说说几个常见的设计模式(23种设计模式)?
    设计一个工厂的包的时候会遵循哪些原则?
    列举一个使用了 Visitor/ Decorator模式的开源项目/库?
    如何实现一个单例?

    代理模式(动态代理)?

    单例模式(懒汉模式,恶汉模式,并发初始化如何解决, volatile与lock的使用)?
    JDK源码里面都有些什么让你印象深刻的设计模式使用,举例看看?

    五、分布式

    什么是CAP定理?

    分布式系统中Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得
    

    说说CAP理论和BASE理论?

    保证基本可用,允许损失部分可用性,实现最终一致性
    

    什么是最终一致性?

    数据和副本是否一致
    

    最终一致性实现方式?

    单数据库:spring声明式事务保证数据库一致性
    分布式系统
        基于消息队列、事务补偿
    

    什么是一致性Hash?

    采用普通hash取余的方式在增删节点会造成数据不可用。一致性hash根据服务器关键字进行hash,服务器在hash环上有固定位置。当数据key进行hash时从遇到第一台服务器上取。
    一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。
    

    如何实现分布式锁?

    通过额外的机制实现数据库锁,
    分别是关系数据库(关系数据库行级锁),
    缓存数据库如redis 的setnx()及expire(),
    zookeeper(同一目录路径下文件名唯一,判断是否最小节点,不是则监听)
    

    如何保证消息的一致性?

    dubbo与springcloud比较

    dubbo由于是二进制的传输,支持多种协议如dubbo,rmi,http,hessian等,通过socket二进制传输占用带宽会更少
    
    springCloud是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大
    

    *dubbo rpc服务依赖的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决

    • springcloud的接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级

    dubbo拓展SPI

    • SPI 全称为 Service Provider Interface,是一种服务发现机制。

    • SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。

    • 这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能

    • Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通ExtensionLoader,我们可以加载指定的实现类。

    • ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象

    • Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下(配置键值对key=接口实现类)

    • 在接口上标识 @SPI 注解

    • loadExtensionClasses 方法总共做了两件事情,一是对 SPI 注解进行解析,二是调用 loadDirectory 方法加载指定文件夹配置文件

    dubboSPI拓展

    调用拦截拓展
    协议拓展
    集群拓展
    路由拓展
    序列化
    注册中心拓展等
    
    • 调用拦截扩展,Dubbo 本身的大多功能均基于此扩展点实现,每次远程方法执行,该拦截都会被执行,请注意对性能的影响
      实现Filter接口
      项目配置:org.apache.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter)

    dubbo配置

    服务,引用,协议,注册中心,生产者,消费者等配置
    

    duboo序列化

    默认Hessian,支持其他,支持拓展
    

    dubbo默认通信框架

    netty
    

    dubbo当一个服务接口有多种实现时怎么做?

    当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可
    

    Dubbo的底层实现原理和机制?

    底层使用用socket通信
    

    描述一个服务从发布到被消费的详细过程?

    生产者被加载实例化,注册到注册中心,消费者订阅服务,消费者获取协议地址进行远程调用。
    

    分布式系统怎么做服务治理?

    采用服务治理框架,如dubbo、springcloud、motan
    

    Dubbo的服务请求失败怎么处理?

    在全局异常中进行包装处理记录日志
    

    dubbo如何实现负载均衡,有哪些算法可以实现?

    随机,轮询,参数哈希,最少调用
    

    Zookeeper的用途,选举的原理是什么?

    zookeeper是一个开源的分布式协调服务
    数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能
    

    zookeeper重要概念

    znode数据节点:zookeeper数据模型为一颗ZnodeTree。分为临时节点和永久节点。永久节点在执行移除前会一直存在,临时节点的声明周期和会话绑定,会话结束该会话绑定的临时节点都会删除
    Session会话:指客户端和zookeeper间会维持一个tcp长连接,客户端通过会话向zookeeper发送请求并接收响应,并且通过该会话获取zookeeper的watcher事件
    Watcher事件监听器:zookeeper允许客户端在Znode上注册一个监听服务,当特定事件被触发时,zookeeper将发送通知到客户端
    

    zookeeper节点状态

    LOOKING选举中
    LEADING主节点。只有leader才能提供写服务,集群中通过zookeeper atomic broadcast Zab协议来保持数据一致性
    FOLLOWING从节点
    OBSERVER观察者状态,不参与投票,仅同步leader状态,拓展系统提高速度
    

    zookeeper选举

    服务器初始化时
    无法和leader保持连接时
    发出投票,接收投票,统计投票,
    默认是采用投票数大于半数则胜出的逻辑,服务器编号大的胜出,半数以上胜出,一般为第三台启动的机器为leader
    
    无法和leader保持连接时,变更looking状态,重新选举流程
    

    zookeeper宕机选举

    集群中必须超过半数投票才能成为leader,只有两台时无法选举leader,5台时只允许挂掉两台,6台时只允许挂掉两台,偶数数量没有意义,为奇数台
    

    讲讲数据的垂直拆分水平拆分?

    垂直拆分:专库专用,按照业务分类,将不同的数据分放在不同的数据库。优点业务清晰维护简单,缺点join及事务控制复杂
    水平拆分:单机瓶颈,将同一个表数据拆分到不同的数据库中。分为分表和分库两种操作。主要考虑的问题为划分维度,处理join、分页问题
    

    zookeeper应用场景

    统一命名服务
    配置管理
    集群管理
    分布式通知/协调
    分布式锁
    分布式队列
    

    zookeeper watch机制?

    zookeeper允许客户端向zookeeper节点注册一个watcher监听,当指定节点被触发时会向指定客户端发出通知,客户端将会从watcherManager中取出watcher对象执行回调逻辑
    

    CAP理论概述

    一致性(C:Consistency)consistency consistency consistency
    可用性(A:Available)available available available available
    分区容错性(P:Partition Tolerance)partition tolerance partition tolerance
    三项中分区容错性是必须的
    

    zookeeper与cap

    zookeeper保证consistency&partition-tolerance
    zookeeper在极端环境中不能保证可用性
    zookeeper在选举过程中不可用
    

    zookeeper集群为何至少需要三个节点

    当只有两个节点时,一个节点宕机将无法满足半数以上节点存活的条件,无法选出leader,没有意义
    

    redis/zk节点宕机如何处理?

    考虑数据备份恢复
    考虑集群
    

    分布式集群下如何做到唯一序列号?

    quartz

    导入依赖
    配置JobDetail关联一个job
    配置Trigger关联JobDetail和日历表达式
    配置Scheduler关联一个Trigger
    

    NGINX

    Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 Nginx 主要提供反向代理、负载均衡、动静分离(静态资源服务)等服务
    

    正向代理与反向代理

    正向:例如VPN,代理用户对目标服务器进行访问
    反向:代理客户端请求,将请求转发给内部服务器
    

    NGINX优点

    1. 高并发、高性能(这是其他web服务器不具有的)
    2. 可扩展性好(模块化设计,第三方插件生态圈丰富)
    3. 高可靠性(可以在服务器行持续不间断的运行数年)
    4. 热部署(这个功能对于 Nginx 来说特别重要,热部署指可以在不停止 Nginx服务的情况下升级 Ngin
    

    你使用过哪些组件或者方法来提升网站性能,可用性以及并发量

    提高硬件能力、增加系统服务器。(当服务器增加到某个程度的时候系统所能提供的并发访问量几乎不变,所以不能根本解决问题)
    使用缓存(本地缓存:本地可以使用JDK自带的 Map、Guava Cache.分布式缓存:Redis、Memcache.本地缓存不适用于提高系统并发量,一般是用处用在程序中。比如Spring是如何实现单例的呢?大家如果看过源码的话,应该知道,Spiring把已经初始过的变量放在一个Map中,下次再要使用这个变量的时候,先判断Map中有没有,这也就是系统中常见的单例模式的实现。)
    消息队列 (解耦+削峰+异步)
    采用分布式开发 (不同的服务部署在不同的机器节点上,并且一个服务也可以部署在多台机器上,然后利用 Nginx 负载均衡访问。这样就解决了单点部署(All In)的缺点,大大提高的系统并发量)
    数据库分库(读写分离)、分表(水平分表、垂直分表)
    采用集群 (多台机器提供相同的服务)
    CDN 加速 (将一些静态资源比如图片、视频等等缓存到离用户最近的网络节点)
    浏览器缓存
    使用合适的连接池(数据库连接池、线程池等等)
    适当使用多线程进行开发。
    

    设计高可用系统的常用手段

    降级: 服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。根据服务方式:可以拒接服务,可以延迟服务,也有时候可以随机服务。根据服务范围:可以砍掉某个功能,也可以砍掉某些模块。总之服务降级需要根据不同的业务需求采用不同的降级策略。主要的目的就是服务虽然有损但是总比没有好;
    限流: 防止恶意请求流量、恶意攻击,或者防止流量超出系统峰值;
    缓存: 避免大量请求直接落到数据库,将数据库击垮;
    超时和重试机制: 避免请求堆积造成雪崩;
    回滚机制: 快速修复错误版本。
    

    微服务领域的发展和看法

    大公司及未来趋势使用的都是springCloud,阿里SpringCloudAlibaba也是springCloud的实现,未来dubbo将无缝集成到SpringCloudAlibaba中
    

    单体应用中如何应对大流量

    简单扩容,如提升硬件能力
    进行拆分
    重新设计架构
    

    大表优化

    限定查询范围
    读写分离
    垂直拆分:将表字段多的拆分成字段少的,优点:表数据变小,减少io,易于维护。缺点:出现冗余,引起join操作
    水平拆分:
        分表:仍在同一个数据库中,数据分表减小单表数据量大的压力。
        分库:支持非常大的数据量,但分片事务难以解决
    

    OAUTH

    OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准,open authorization开放授权 
    spring对oauth的支持,可以和springSecurity进行集成
    第三方带上回调地址请求授权服务器
    服务器认证成功,带上code跳转至回调地址
    第三方服务器带上code请求资源服务器
    资源服务器返回相应资源(比如用户ID ,头像等非敏感资源)
    

    过滤器和拦截器

    Filter是依赖于Servlet容器的,可以修改 request, 可以用来拦截静态资源,作用于每次请求。常用到的为CharacterEncodingFilter,DispatcherServlet
    Incerpector 可以访问context容器,原理为反射,可以具体到方法。需要继承HandlerInterceptorAdapter
    应用场景:日志记录,权限检查
    

    相关文章

      网友评论

          本文标题:葵花宝典-java面试题

          本文链接:https://www.haomeiwen.com/subject/tvaflqtx.html