面经2020.3.5

1、说下HashMap底层是数组+链表如何通过key-value的形式存储数据的?

https://blog.csdn.net/weixin_44460333/article/details/86770169

 

2、线程池的参数?参数的意思?10个线程,5条核心线程,有哪些线程一直在队列中?

一、corePoolSize 线程池核心线程大小

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。

二、maximumPoolSize 线程池最大线程数量

一个任务被提交到线程池后,首先会缓存到工作队列(后面会介绍)中,如果工作队列满了,则会创建一个新线程,然后从工作队列中的取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize来指定。

三、keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

四、unit 空间线程存活时间单位

keepAliveTime的计量单位

五、workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现。

六、threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

七、handler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:

①CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

②AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

③DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

核心线程满了,接下来进队列,队列也满了,创建新线程,直到达到最大线程数,之后再超出,会进入拒绝rejectedExecution

 

3、Spring 如何解决循环依赖的问题?

Spring的循环依赖的理论依据其实是基于Java的引用传递,当我们获取到对象的引用时,对象的field或zh属性是可以延后设置的(但是构造器必须是在获取引用之前)。

   Spring的单例对象的初始化主要分为三步: 


    ①:createBeanInstance:实例化,其实也就是 调用对象的构造方法实例化对象

    ②:populateBean:填充属性,这一步主要是多bean的依赖属性进行填充

    ③:initializeBean:调用spring xml中的init() 方法。

从上面讲述的单例bean初始化步骤我们可以知道,循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖。

那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。

  https://blog.csdn.net/qq_36381855/article/details/79752689

 

4、说说队列的数据结构?使用场景?

 

5、说说重入锁ReentrantLock?对于静态方法与非静态方法使用关键字synchronized?

       简单来讲,就是增强版synchronized​,在jdk1.5的时候,ReentranceLock要比synchronized在性能上增强很多,从jdk1.6开始,由于synchronized​做了很多优化,基本和ReentrantLock性能持平,《深入理解jvm虚拟机》上建议1.6以后优先使用synchronized。

           a.重入:

           对于synchronized​来讲,被synchronized锁定的资源(代码块),线程A,只有执行完毕,才能释放锁,对于长时间的同步块来讲,其他线程线程B在很长时间内都得不到执行,如果B想中断自己,在synchronized锁定下,这种情况B不会中断。

           ReentranceLock之所以可以重入,是因为,线程在执行的过程可以中断,对于某些等待时间较长的同步块,可以中断,而转去执行其他的操作。

           引申:synchronized​可能会产生死锁,ReentranceLock可以中断死锁。

           b.公平锁

           公平锁:公平意思是,按照申请锁的时间,先来先得,有序。

           synchronized​是非公平锁,优先级高的线程可以优先得到锁。

           ReentranceLock默认也是非公平锁,可以通过构造函数实现公平锁

           c.多条件

            ReentranceLock可以同时绑定多个Condition,

            synchronized只能绑定一个Condition,也就是锁定的对象。

synchronized静态同步方法,由于静态方法优先于对象存在,所以锁是该类的字节码对象(.class文件)

synchronized非静态同步方法,锁是该类对象或this;

 

6、说说什么是微服务?单体服务和微服务的优缺点?

微服务一种系统架构的设计风格,主旨是将原本复杂的系统拆分成多个独立的小型服务,每个服务维护着自身的业务逻辑、数据处理以及部署,服务和服务之间通过简单的通信协议进行通信(比如说Restful API),不要求每个微服务使用同一种变成语言编写。

传统的单体应用:

面临的问题

1项目过度复杂:比如原本一个很简单的单体应用,经过不断的拓展,功能越来越多,经手的人也在不断的变化,可能到最后已经变成一个非常复杂的大系统了,而且这种复杂情况还会越来越严重。

2开发速度缓慢

因为单体应用复杂了之后,项目会越来越臃肿而且庞大,每一次编译构建运行测试,都要花费大量的时间和精力,而且如果测试有问题,又要重新来一次,有种牵一发而动全身的操作。

3不易拓展

比如部署的时候需要的服务器性能要满足所有功能的要求,比如内存,CPU等

4技术栈不易拓展

项目开始的时候一旦选择了某一种技术栈来开发项目,那么以后就很难在技术栈上做切换。有时候因为某一个功能需要改新的技术去做,那么这是很难去重新改造这个模块的。

曾经的优势

1开发简单,一个IDE可以很快速的就构建出一个单体应用

2测试简单

3部署简单,一个tomcat安装之后把应用放上去就可以了

4集群化部署也很容易,多个tomcat + 一个Nginx就可以搭建好集群环境了

微服务的优势

1大项目可以持续交付

微服务将一个大项目拆分成很多个互相独立的服务,每一个服务都可以由一个团队去完成,并且配备自己的开发和部署,各个团队开发的微服务相互独立,互不干扰。每一个小项目都可以非常方便的进行测试部署,不会牵一发而动全身。

2易于维护

一个传统的单体项目,刚接手的时候不一定能很快的理清头绪,但是微服务由于比较小巧,一个微服务只负责一个功能,能很快的理出头绪上手开发。并且微服务的规模都比较小,项目启动和测试速度都会比较快。

3服务可以可以独立拓展

独立拓展可以让我们充分的使用硬件资源。单体应用所有的功能都写在一起,有的模块可能需要内存更大,有的模块需要CPU的运算更大,部署的时候,我们只能选择CPU更强内存更大的机器,而如果是微服务架构,不同的系统独立部署,压力大的时候进行独立的集群化部署,这些操作都不会影响到其他的服务,非常方便灵活。

4更强的兼容性

由于每一个微服务都是独立运行的,处理的当,我们在微服务架构中可以实现更好的故障隔离,当一个微服务发生问题时,不会影响到其他的功能服务。

5可以灵活的采用最新的技术

因为微服务都是独立运行的,单个微服务的技术升级非常简单和容易,

微服务的弊端

1服务的拆分

2分布式系统带来的挑战

主键如何产生、如何熔断、分布式事务如何处理、数据如何同步等一系列问题

3多个研发团队的协调管理

不同的团队研发不同的微服务,那么就需要协调多个团队共同配合,才能做好微服务的开发工作,这堆项目管理提出了挑战。
 

7、dubbo都有哪些角色组成?Container的作用?如何理解服务治理?

服务容器 Container 负责启动,加载,运行服务提供者。
服务提供者Provider在启动时,向注册中心注册自己提供的服务。
服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。
注册中心Registry返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务治理:集群、路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等手动配置

 

8、@SpringBootApplication注解是由哪些注解组成的?

@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

 

9、SpringBoot和SpringCloud的不同?

  SpringBoot是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了Spring众多框架中所需的大量且繁琐的配置文件,所以 SpringBoot是一个服务于框架的框架,服务范围是简化配置文件。(starter快速整合三方框架、去xml配置注解开发、内置Tomcat和netty服务)

 Spring Cloud是一个微服务框架,相比Dubbo等RPC框架, Spring Cloud提供的全套的分布式系统解决方案

SpringCloud 的核心组件:服务发现——Netflix Eureka;客服端负载均衡——Netflix Ribbon;断路器——Netflix Hystrix;服务网关——Netflix Zuul;分布式配置——Spring Cloud Config

 

9、说说SpringBoot内置netty服务?

 

10、Spring有哪些主要模块?

Spring有七大功能模块,分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。

Spring Core:Core是Spring的核心类库,Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Sprign的所有功能都是借助IOC实现的。

AOP:AOP模块是Spring的AOP库,提供了AOP(拦截器)机制,并提供常用的拦截器,供用户自定义和配置。

ORM:Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,ibtas,jdao等框架的支持,Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理

DAO模块:Spring 提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,并能统一管理JDBC事物,并不对JDBC进行实现。(执行sql语句)

WEB模块:WEB模块提供对常见框架如Struts1,WEBWORK(Struts 2),JSF的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器。

Context模块:提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。

MVC模块:为Spring提供了一套轻量级的MVC实现,在Spring的开发中,我们既可以用Struts也可以用Spring自己的MVC框架,相对于Struts,Spring自己的MVC框架更加简洁和方便
 

11、Spring 常用的注入方式有哪些?

Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:构造方法注入,setter注入,基于注解的注入

 

12、Spring事务实现方式有哪些?

(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

(2)基于 TransactionProxyFactoryBean的声明式事务管理

(3)基于 @Transactional 的声明式事务管理

(4)基于Aspectj AOP配置事务

 

13、spring切面和切点的定义?如何使用的?

  • 通知: 
    • 定义:切面也需要完成工作。在 AOP 术语中,切面的工作被称为通知。
    • 工作内容:通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决何时执行这个工作。
    • Spring 切面可应用的 5 种通知类型:
  1. Before——在方法调用之前调用通知
  2. After——在方法完成之后调用通知,无论方法执行成功与否
  3. After-returning——在方法执行成功之后调用通知
  4. After-throwing——在方法抛出异常后进行通知
  5. Around——通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
  • 连接点: 
    • 定义:连接点是一个应用执行过程中能够插入一个切面的点。
    • 连接点可以是调用方法时、抛出异常时、甚至修改字段时、
    • 切面代码可以利用这些点插入到应用的正规流程中
    • 程序执行过程中能够应用通知的所有点。
  • 切点: 
    • 定义:如果通知定义了“什么”和“何时”。那么切点就定义了“何处”。切点会匹配通知所要织入的一个或者多个连接点。
    • 通常使用明确的类或者方法来指定这些切点。
    • 作用:定义通知被应用的位置(在哪些连接点)
  • 切面: 
    • 定义:切面是通知和切点的集合,通知和切点共同定义了切面的全部功能——它是什么,在何时何处完成其功能。
  • 引入: 
    • 引入允许我们向现有的类中添加方法或属性
  • 织入: 织入是将切面应用到目标对象来创建的代理对象过程。                                                                                                 切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可以织入
  • 编译期——切面在目标类编译时期被织入,这种方式需要特殊编译器。AspectJ的织入编译器就是以这种方式织入切面。
  • 类加载期——切面在类加载到JVM ,这种方式需要特殊的类加载器,他可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5 的 LTW 就支持这种织入方式
  • 运行期——切面在应用运行期间的某个时刻被织入。一般情况下,在织入切面时候,AOP 容器会为目标对象动态的创建代理对象。Spring AOP 就是以这种方式织入切面。

使用:

package com.yidongxueyuan.spring.pojo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component("myAspectAnto")
//告知spring 该类是一个切面类: 
@Aspect
public class MyAspectAnto {
	
	@Pointcut(value="execution ( * com.yidongxueyuan.spring.dao.impl.*.*(..))")
	private void point1() {}
	
	
	
	/*@Before(value="point1()")
	public void checkPri() {
		System.out.println("权限的校验");
	}
	
	@AfterReturning(value="point1()")
	public void logger() {
		System.out.println("日志的记录: ");
	}
	
	
	@AfterThrowing(value="point1()",throwing="e")
	public void afterThrowing(Throwable e) {
		System.out.println("异常抛出通知。。。"+e.getMessage());
	}
	
	@After(value="point1()")
	public void after() {
		System.out.println("最终通知。。。");
	}*/
	
	//环绕通知; 
	@Around(value="point1()")
	public Object around(ProceedingJoinPoint joinPoint) {
		Object obj=null; 
		try {
			System.out.println("前置通知1。。。");
			obj = joinPoint.proceed();
			System.out.println("后置通知1。。。");
		} catch (Throwable e) {
			System.out.println("异常抛出通知1。。。");
			e.printStackTrace();
		} finally {
			System.out.println("最终通知1");
		}
		return obj;
	}
	
	
	
}

 

14、SpringMVC工作流程描述?
      1. 用户向服务器发送请求,请求被SpringMVC 前端控制DispatcherServlet捕获;

      2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;

      3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)

       4.  提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

      HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

      数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

      数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

      数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

      5.  Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

      6.  根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;

      7. ViewResolver 结合Model和View,来渲染视图

      8. 将渲染结果返回给客户端。
 

15、springMVC的注解?rest风格

@Controller:

       用于定义控制器类

@ResponseBody:

       表示方法的返回结果直接写入HTTP response body中

@PathVariable:

       获取路径参数

@RquestParam:

       用在方法的参数前面

@RequestBody

@RestController:

       是@Controller和@ResponseBody的合集

@RequestMapping:

       提供路由信息,负责URL到Controller中的具体函数的映射

@GetMapping:

       是@RequestMapping(method = RequestMethod.GET)的缩写。不支持@RequestMapping的自定义属性。

@PostMapping:

      是@RequestMapping(method = RequestMethod.POST)的缩写。不支持@RequestMapping的自定义属性。

@ControllerAdvice:统一处理异常。

@ExceptionHandler:用在方法上表示遇到这个异常就执行以下方法。

     Controller层的全局异常统一处理

@RequestMapping("/restfulTest")
@Controller
public class RestTestHandler {
 
	private static final String SUCCESS="success";
	/**
	 * 1. 使用 @RequestMapping 注解来映射请求的 URL
	 * 2. 返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图 
     解析器, 会做如下的解析:
	 * 通过 prefix + returnVal + 后缀 这样的方式得到实际的物理视图, 然会做转发操作
	 * 
	 * /WEB-INF/views/success.jsp
	 * 
	 * @return
	 */
	 @RequestMapping(value="/testRest/{id}",method=RequestMethod.DELETE)
	   public String testDelete(@PathVariable Integer id){
		   System.out.println(" TestRest DELETE:"+id);
		   return SUCCESS;
	   }
 
	   @RequestMapping(value="/testRest/{id}",method=RequestMethod.PUT)
	   public String testPut(@PathVariable Integer id){
		   System.out.println(" TestRest PUT:"+id);
		   return SUCCESS;
	   }
	   
	   @RequestMapping(value="/testRest",method=RequestMethod.POST)
	   public String testPost(){
		   System.out.println(" TestRest POST:");
		   return SUCCESS;
	   }
	
	
   @RequestMapping(value="/testRest/{id}",method=RequestMethod.GET)
   public String testRest(@PathVariable Integer id){
	   System.out.println(" TestRest Get:"+id);
	   return SUCCESS;
   }
	
}

 

16、Spring自动装配?
一、@Autowired
二、@Resource
三、@Inject
1.@Autowired:自动注入
  (1)、默认优先按照类型去容器中寻找相应的组件
        applicationContext.getBean(BookDao.class);
  (2)、如果找到多个类型相同的组件,再将属性的名称作为组件的id去容器中寻找
         applicationContext.getBean("bookDao);
  (3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
  (4)、自动装配默认属性要装好,否则会报错
           可以使用@Autowired(required=false);
  (5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean


2.@Resuorce:JSR250
 (1)、可以和@Autowired一样进行自动装配
       public class BookService{
               @Resource
               private BookDao bookDao
   }
 (2)、默认按照组件名称进行装配,设置name="bookDao2",可以指定名称
 (3)、不支持@Primary以及@Autowired(required=false)


3.@Inject:JSR330
(1)在maven中查找依赖javax.inject,添加依赖进入工程
(2)能支持@Autowired的各种特性,但需要添加依赖,不支持required=false


4.总结
(1)@Autowired是Spring定义的,其余两个都是JAVA规范
(2)完成解析自动装配的是实现了BeanPostProcesser的AutowiredAnnotationBeanPostProcesser
 

17、@Autowired 与@Resource的区别?

@Resource的作用相当于@Autowired,只不过@Autowired按类型(byType)自动注入,而@Resource默认按名称(byName)自动注入。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
  @Resource装配顺序
  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

 

18、spring security的了解?

https://blog.csdn.net/qq_32734365/article/details/81413236

19、Shiro的使用?

Shiro的 SecurityManager

https://blog.csdn.net/mxw2552261/article/details/79674871

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值