1.简述spring的优势与劣势
优点: 有了IOC容器,对象间依赖关系交给spring,更专注业务逻辑代码。 spring中避免了关键字new造成的耦合问题。 spring本身就是一个工厂,不需要再编写工厂类了。 spring不需要进行明确的引用关系的传递,直接通过配置完成 所有框架几乎都可以在spring中整合在一起使用。 spring编程=factory设计模式+proxy设计模式 缺点: spring不容易拆分 springJSP代码过多,过于灵活缺乏一个公用的控制器,不适合分布式
2.什么是Spring的IOC?
ioc:(中文:控制反转)是 spring 的核心,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。 控制指的是当前对象对内部成员的控制权;控制反转指的是,这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。 由Spring通过java的反射机制根据配置文件在运行时动态的创建实例,并管理各个实例之间的依赖关系。 对象与对象之间松散耦合,有利于功能的扩展和复用。 IoC的主要实现方式有两种:依赖查找、依赖注入。
3.什么是Spring的Aop?
aop是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP主要一般应用于签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等。 切面(Aspect):共有功能的实现 通知(Advice):切面的具体实现 连接点(JoinPoint):程序在运行过程中能够插入切面的地点 切入点(Pointcut):用于定义通知应该切入到哪些连接点上 目标对象(Target):那些即将切入切面的对象,也就是那些被通知的对象 代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象 织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程
4.Spring的循环依赖是什么? Spring是如何解决的?
循环依赖,其实就是循环引用,就是两个或者两个以上的 bean 互相引用对方,最终形成一个闭环,如 A 依赖 B,B 依赖 C,C 依赖 A。 Spring 解决循环依赖有两个前提条件: 1.不全是构造器方式的循环依赖 2.必须是单例 解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化完全的对象。 第一级缓存:用来保存实例化、初始化都完成的对象 第一级为 singletonObjects 第二级缓存:用来保存实例化完成,但是未初始化完成的对象 第二级为 earlySingletonObjects 第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象 第三级为 singletonFactories
5.Spring的Bean的生命周期是什么?
spring生命周期中的阶段,包括初始化、使用、销毁 1、初始化阶段 1)调用bean的构造函数,创建实例; 2)进行参数依赖注入; 3)若实现beans.BeanNameAware接口,则调用BeanNameAware的setBeanName()方法; 4)若实现beans.factory.BeanClassLoaderAware接口,则调用BeanClassLoaderAware的setBeanClassLoader()方法; 5)若实现context.ApplicationContextAware接口,则调用ApplicationContextAware的setApplicationContext()方法; 6)若使用了注解@PostConstruct,则调相应方法; 7)若实现beans.factory.InitializingBean接口,则调用InitializingBean接口的afterPropertiesSet方法; 8)若bean定义的使用了initMethod,则调相应方法; 9)若实现beans.factory.config.BeanPostProcessor接口,则调用BeanPostProcessor的postProcessBeforeInitialization()方法 和postProcessAfterInitialization方法; 2、使用阶段 bean在项目的使用; 3、销毁阶段 1)若使用注解@PreDestroy,则调用相应方法; 2)若bean定义中配置了destroyMethod,则调用相应方法; 3)若实现beans.factory.DisposableBean接口, 则调用DisposableBean接口的destroy方法;
6.SpringMVC的执行流程是?
(1)用户发送请求至前端控制器DispatcherServlet; (2)DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle; (3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器一并返回给DispatcherServlet (4)DispatcherServlet通过HandlerAdapter处理器适配器调用处理器; (5)执行处理器; (6) Handler执行完成返回ModelAndView; (7) HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;(9)ViewResolver解析后返回具体View; (10)DispatcherServlet对View进行渲染视图 (11)DispatcherServlet响应用户
7.SpringMVC是如何解析传入的JSON为实体类对 象的?
通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。 (1)加入Jackson.jar (2)在配置文件中配置json的映射 (3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。
8.SSM项目中的注解有哪些,并介绍注解的作用
@RequestMapping 将 http 请求映射到相应的类/方法上 @Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作, 通过@Autowired 的使用来消除 set/get 方法。 @Controller-用于Spring MVC项目中的控制器类。Service -用于服务类。 @ResponseBody-用于发送Object作为响应,通常用于发送XML或JSON数据作为响应。@PathVariable-用于将动态值从URI映射到处理程序方法参数。 @Aspect,@Before,@After,@Around,@Pointcut-用于切面编程(AOP) @Configuration,@ComponentScan和@Bean-用于基于java 的配置 @Scope-用于配置spring bean的范围 @Service:此注解是组件注解的特化 @Repository:这个注解是具有类似用途和功能的 @Component注解的特化
9.Mybatis是如何进行接口与xml的映射?
Mapper用于映射SQL语句,可以说是MyBatis操作数据库的核心特性之一 mapper - namespace <!-- 将mapper文件加入到配置文件中 --> resultMap - 用来描述数据库结果集和对象的对应的关系 <!--reusltMap ID有唯一性--> <resultMap id="userList" type="User"> <!--result结果标签,property实体类变量,column数据库字段--> 配置了一个mapperLocations属性,它是一个表达式,sqlSessionFactory会根据这个表达式读取包com.xxx.mybaits.mapper下面的所有xml格式文件 <!--映射一个嵌套JavaBean属性,一对一 这里对应的是实体类里的 role类型的变量--> association 映射一个嵌套JavaBean属性,一对一 <!--映射一个嵌套集合属性,一对多,类似于联表查询--> collection 映射一个嵌套集合属性,一对多
10.Mybatis的优势是什么?# 与$的区别是?
Mybatis是开源的半ORM框架的技术 优势: Mybatis支持普通的SQL查询、存储过程和高级映射的持久层框架。 Mybatis将大量的SQL语句从程序里面剖离出来,配置在配置文件中,实现SQL的灵活配置。 #{}是预编译处理,$是字符串替换。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement 的set方法来赋值;Mybatis在处理${}时,就是把$替换成变量的值。 使用#{}可以有效的防止 SQL注入,提高系统安全性。
11.Linux的常用命令?
cd:就是切换目录 cd / :进入到Linux跟目录 cd 路径/或者具体的目录名称 cd /usr/local:进入多级目录 cd usr 进入指定的目录中 cd .. 回退上级目录 ls 罗列当前目录下面的所有的文件以及目录的名称 ls -a 全部的文件以及文件夹的名称以及包含的隐藏文件 ll 罗列当前所有的文件以及文件夹的名称的详情信息 创建文件夹 mkdir 文件夹名称 mv 源文件 路径: 表示剪切源文件到指定的路径下 cp 文件 路径:复制 文件到指定的文件夹下 rm -rf 目录/文件(递归删除目录的),暴力删除 rm 文件名称 删除指定文件,询问是否删除 y,删除 ,n 不删除 clear清屏命令 ps -a 查看当前进程id ps -ef|grep tomcat 搜索指定的软件的进程的信息
12.Docker的常用命令?
docker run -i -t <IMAGE_ID> /bin/bash:-i:标准输入给容器 -t:分配一个虚拟终端 /bin/bash:执行bash脚本 -d:以守护进程方式运行(后台) -P:默认匹配docker容器的5000端口号到宿主机的49153 to 65535端口 -p <HOT_PORT>:<CONTAINER_PORT>:指定端口号 - -name: 指定容器的名称 - -rm:退出时删除容器 docker stop <CONTAINER_ID>: 停止container docker start <CONTAINER_ID> : 重新启动container docker ps - Lists containers. -l:显示最后启动的容器 -a:同时显示停止的容器,默认只显示启动状态 docker attach <CONTAINER_ID> 连接到启动的容器 docker logs <CONTAINER_ID> : 输出容器日志 docker cp <CONTAINER_ID>:path hostpath:复制容器内的文件到宿主机目录上 docker rm <CONTAINER_ID>:删除container docker rm `docker ps -a -q`:删除所有容器 docker kill `docker ps -q` docker rmi `docker images -q -a` docker wait <CONTAINER_ID>:阻塞对容器的其他调用方法,直到容器停止后退出 docker top <CONTAINER_ID>:查看容器中运行的进程 docker diff <CONTAINER_ID>:查看容器中的变化 docker inspect <CONTAINER_ID>:查看容器详细信息(输出为Json) -f:查找特定信息,如 docker inspect - f '{{ .NetworkSettings.IPAddress }}' docker commit -m "comment" -a "author" <CONTAINER_ID> ouruser/imagename:tag docker extc -it <CONTAINER> <COMMAND>:在容器里执行命令,并输出结果
13.说说你了解的安全框架?并介绍认证/授权流程
Shiro——Shiro认证、授权 认证流程 1.获取当前的Subject, 调用SecurityUtils.getSubject(); 2.测试当前用户是否已经被认证, 即是否已经登录, 调用Subject的isAuthentication() 3.若没有被认证, 则把用户名和密码封装为UsernamePasswordToken对象 创建一个表单页面 把请求提交到Controller中 获取用户名和密码 4.前台执行登录, 调用Subject的login(AuthenticationToken)方法 5.自定义Realm, 从数据库中获取对应的记录, 返回给Shiro 自定义的Realm需要继承org.apache.shiro.realm.AuthorizingRealm类 实现protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)方法 实现方法中的参数就是前台中login方法中的token 6.由shiro内部自动完成密码的比对 授权流程 自定义的Realm继承AuthorizingRealm类实现protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)方法
14.Springboot的自动装配原理
SpringBoot通过main方法启动SpringApplication类的静态方法run()来启动项目。 根据注释的意思,run方法从一个使用了默认配置的指定资源启动一个SpringApplication并返回ApplicationContext对象 @SpringBootConfiguration:这个注解的底层是一个@Configuration注解,意思被@Configuration注解修饰的类是一个IOC容器,支持JavaConfig的方式来进行配置; @ComponentScan:这个就是扫描注解的意思,默认扫描当前类所在的包及其子包下包含的注解,将@Controller/@Service/@Component/@Repository等注解加载到IOC容器中; @EnableAutoConfiguration:这个注解表明启动自动装配,里面包含连个比较重要的注解@AutoConfigurationPackage和@Import SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories文件中的所有自动配置类,并对其加载,这些自动配置类都是以AutoConfiguration结尾来命名的。它实际上就是一个JavaConfig形式的IOC容器配置类,通过以Properties结尾命名的类中取得在全局配置文件中配置的属性,如server.port。 *Properties类的含义:封装配置文件的相关属性。 *AutoConfiguration类的含义:自动配置类,添加到IOC容器中。
15.Jpa是如何进行使用的?注解有哪些?作用是?
jpa 全称 Java Persistence API,是 Java 持久化接口规范 @Entity,@Table,声明主键@Id,@GeneratedValue 声明普通属性 @Column value method; value:指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明); method:指定请求的method类型, GET、POST、PUT、DELETE等; consumes,produces; consumes:指定处理请求的提交内容类型(Content-Type) produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回; params,headers; params:指定request中必须包含某些参数值是,才让该方法处理。 headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
16.Redis是什么?存储结构?存储类型?持久化方式?三大场景问题?应用场景?淘汰策略?
Redis是基于内存的非关系型数据库 高速缓存数据库 Redis 支持的数据类型:string(字符串)、list(列表)、hash(字典)、set(集合)、 zset(有序集合) redis的三大场景问题: 1.缓存的穿透 当用户使用数据库不存在的key进行访问时,会穿透过Redis直接访问到数据库解决方案:放置null值,设置失效时间 2.缓存击穿 缓存的击穿指,当前的redis中的key持续的被高并发所进行请求,当key突然失效时,则高并发的请 求会全部请求到数据库,造成数据库的压力的提升。针对于热点数据,可以设置永不失效 3.缓存的雪崩 针对于热门商品,设置失效时间短一些,针对冷门商品设置失效时长长一些,尽最避免我们的缓存同 一时间失效
17.nginx是什么?作用是什么?有哪些负载均衡的策略?
Nginx是一个高性能的HTTP和反向代理服务器,及电子邮件代理服务器,同时也是一个非常高效的反向代理、负载平衡。负载均衡是通过反向代理实现的 Nginx的作用: 1、作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。能够支持高达 50,000 个并发连接数的响应 2、作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。 3、作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。 4、Nginx 安装非常的简单,配置文件 非常简洁,Bugs非常少的服务器: Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。 负载均衡的策略 1.轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 2、指定权重 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 3、IP绑定 ip_hash 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
18.mysql的索引是什么?如何进行设置?
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。 索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。 索引的种类 普通索引:仅加速查询 唯一索引:加速查询 + 列值唯一(可以有null) 主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个 组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并 全文索引:对文本的内容进行分词,进行搜索 设置索引 1.添加PRIMARY KEY(主键索引) 语法:ALTER TABLE `表名` ADD PRIMARY KEY ( `列名称` ) mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 2.添加UNIQUE(唯一索引) 语法:ALTER TABLE `表名` ADD UNIQUE ( `列名称`) mysql>ALTER TABLE `table_name` ADD UNIQUE ( `column`) 3.添加INDEX(普通索引) 语法:ALTER TABLE `表名` ADD INDEX index_name ( `列名称` ) mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column` ) 4.添加FULLTEXT(全文索引) 语法:ALTER TABLE `表名` ADD FULLTEXT ( `列名称`) mysql>ALTER TABLE `table_name` ADD FULLTEXT ( `column`) 5.添加多列索引 语法:ALTER TABLE `表名` ADD INDEX index_name ( `列名称`, `列名称`, `列名称` ) mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )
19.写出最擅长的排序方式(除了冒泡排序)
1.选择排序(Select Sort): 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。 int[] arry= {7,4,8,3}; for(int i = 0;i<arry.length-1;i++){ int minIndex=i; int minArry=arry[i]; for (int j = i+1;j<arry.length;j++){ if(minArry>arry[j]){ minIndex=j; minArry=arry[j]; } } if(minIndex!=i){ arry[minIndex]=arry[i]; arry[i]=minArry; } System.out.println(Arrays.toString(arry)); } 2.冒泡排序(Bubble Sort): 传统的冒泡排序需要依次比较相邻的两个元素,按照升序或者降序的规则进行交换 int arr[]={6,2,3,4,0}; int change=0; Boolean flag=false; for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ flag=true; change=arr[j]; arr[j]=arr[j+1]; arr[j+1]=change; } } if(!flag){ break; }else { flag=false; } System.out.println("第"+(i+1)+"趟"+Arrays.toString(arr)); } 3.插入排序(Inser Sort): 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法 int arry[]={7,5,4,3,2}; for(int i=1;i<arry.length;i++){ int insertVal = arry[i]; int insertIndex=i-1; while(insertIndex >= 0 && insertVal<arry[insertIndex]){ arry[insertIndex+1]=arry[insertIndex]; insertIndex--; } if(insertIndex+1!=i){ //此时无需交换 arry[insertIndex+1]=insertVal; } System.out.println(Arrays.toString(arry)); }
20.说出最熟悉的设计模式,以及是怎么在程序中应用的?
• 单例模式:保证被创建一次,节省系统开销。 • 工厂模式(简单工厂、抽象工厂):解耦代码。 简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。 工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。 抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。 • 观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。 • 外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。 • 模版方法模式:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。 • 状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。