一、Spring
两大核心IOC和IOP;
1. IOC:控制反转
我们在之前开发时,如果在一个类中想要使用其他类的对象的时候,都采用的NEW的方式,或者高级一点的就是反射来获取对对象的实例,这样的层与层、类与类之间的耦合度就会大大的增加,并且在程序中会出现硬编码的问题
而spring的IOC就很好的解决了这个问题,如果在一个类中使用另一个类的实例对象时,
只需要定义一个接口类型的类或者成员变量,
由使用者为我们注入具体的实现类对象,从而可以达到解耦和
实现IOC思想有两种方式
依赖注入:(简称DI)
依赖查找:(简称DL)
而依赖注入使用的更广泛
IOC解决对象之间的依赖问题,把所有Bean的依赖关系通过配置文件或注解关联起来,降低了耦合度
2. IOP:面向切面编程
一开始学习的java是面向对象编程的,他有好处也有缺点,
比如:我们在实际开发中都会有一根业务主线(即用户的需求),而我们则是围绕这跟主线来实现核心的方法,但是,有时候会有一些业务跟主线没有关系,比如:权限、事物、日志等等。
但是会和业务的核心方法有交织在一起,这样我们的开发会比较麻烦,代码量也会比较多,
而Spring的AOP面向切面编程就很好的解决了这个问题,
他把和业务主线没有关系的功能进行分离开,在需要这些方法的时候随时可以加入
这样,我们就能更关注与需求和业务上,
将与业务主线无关但又和业务核心方法交织在一起的功能进行分离,在需要的时候随时注入,解决了开发中代码的庸余,让我们在开发中更关注业务和需求
底层是动态代理,根据实际的情况会选择使用基于子类的还是使用基于接口的动态代理
3. 为什么要用spring
Spring是一个轻量级的开源框架,官方宗旨也给出了明确的说明,简化开发,以实战为主,使用Spring可以解决对象之间的以来问题,减低层与层之间的耦合度,并且能够分离业务主线和核心方法,可以很好的整合第三方框架
4. bean的生命周期
bean 默认情况下是单例的,但是没有执行销毁方法。
bean:出生 活着 死亡
a) 出生:使用立即加载方式,spring容器一创建,bean对象就已经都创建好了,实例化bean和初始化bean就都执行了。
b) 活着:spring容器还在,bean对象就一直在。
c) 死亡:spring容器如果没了,bean对象也就消亡了。
5. Spring 在ssm中起什么作用
作用于Bean工厂,用来管理Bean的生命周期和框架集成。
6. Spring的事务分类
Spring支持编程式事务管理以及声明式事务管理两种方式。
编程式事务管理:编程方式管理事务,极大灵活性,难维护。
声明式事务管理:可以将业务代码和事务管理分离,用注解和xml配置来管理事务。
7. 事务的传播机制
事务的第一个方面是传播行为(propagation behavior)。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:
- PROPAGATION_REQUIRED: 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
- PROPAGATION_SUPPORTS: 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
- PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
- PROPAGATION_REQUIRED_NEW:表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
- PROPAGATION_NOT_SUPPORTED:表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
- PROPAGATION_NEVER:表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
- PROPAGATION_NESTED:表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务
8. 事务的特性
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):事务与事务之间是相互隔离,相互不干扰的。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响
9. 事务失效的情况
10. 事务的隔离级别
隔离级别 |
含义 |
ISOLATION_DEFAULT |
使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED |
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
ISOLATION_READ_COMMITTED |
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
ISOLATION_REPEATABLE_READ |
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
ISOLATION_SERIALIZABLE |
最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |
11. 不考虑隔离级别的情况下会出现的问题
- 脏读(Dirty reads)—一个事务读取到了另一个事务修改但未提交的数据。
- 不可重复读(Nonrepeatable read)—多次读取到的数据不相同。
- 幻读(Phantom read)—多次读取到的数据数量不同
12. Spring主要使用了什么设计模式
工厂模式:每个Bean的创建通过方法
单例模式:默认的每个Bean的作用域都是单例
代理模式:关于Aop的实现通过代理模式
13. IOC,AOP的实现原理
IOC:通过反射机制生成对象注入
AOP:动态代理
14. Spring常用注解
@EnableWebMvc
@Controller
@RequestMapping
@ResponseBody
@RequestBody
@PathVariable
@RestController
@ControllerAdvice
@ModelAttribute
@Transactional
@JsonIgnore
@JsonFormat
@Component:泛指各种组件,@Controller、@Service、@Repository都可以称为@Component。
@Controller:控制层
@Service:业务层
@Repository:数据访问层
二、SpringMVC
1. 什么是MVC
MVC是模型(model)-视图(view)-控制器(controller)的缩写
一种软件设计思想, 强制性的把应用程序的输入、处理和输出分开。解耦和,
- 视图: 视图是用户看到并与之交互的界面。视图向用户显示相关的数据,并接受用户的输入。视图不进行任何业务逻辑处理。--获取数据/显示数据
- 模型: 模型表示业务数据和业务处理。相当于JavaBean。一个模型能为多个视图提供数据。这提高了应用程序的重用性。--处理数据(model层对容器的依赖性越少越好,model层是多实例还是单例)
- 控制器: 当用户单击Web页面中的提交按钮时,控制器接受请求并调用相应的模型去处理请求。
然后根据处理的结果调用相应的视图来显示处理的结果。 --控制流程
2. MVC的处理过程
首先控制器接受用户的请求,调用(委托)相应的模型来进行业务处理,并返回数据给控制器。控制器调用相应的视图来显示处理的结果。并通过视图呈现给用户。
3. 为什么要使用SpringMVC?
最主要目的就是为了解耦和
4. SpringMvc中控制器的注解
@Controller:该注解表明该类扮演控制器的角色
5. SpringMVC的设计模式
第一部分:
当容器(tomcat)启动时会加载web.xml,初始化DisPatcherServlet控制器
第二部分:
当用户页面发送请求时DisPatcherServlet会接收请求转发到HandlerMapping,
HandlerMapping接收到请求后回去找对应的controller类,将执行结果(chain)返回到DisPatcherServlet控制器,
因为返回的是chain,所以不能直接调用方法,需要将chain转发到HandlerAdapter,
HandlerAdapter接收到请求后回去执行对应的controller类中的方法,controller会将执行结果modelAndView返回给HandlerAdapter,
HandlerAdapter再将modelAndView返回给DisPatcherServlet
DisPatcherServlet再将modelAndView转发给ViewResolver进行视图解析得到model数据,再返回给DisPatcherServlet,
DisPatcherServlet将接收到的model数据转发给view进行视图渲染,view会将渲染结果(页面)返回给DisPatcherServlet
DisPatcherServlet会将最终页面相应给浏览器
三、Mybatis
-
Mybatis概念
MyBatis是apache下一个优秀的持久层框架,
它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,
而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
-
Mybatis框架的优点
1) 使用数据库连接池对连接进行管理(不再是频繁的开启和关闭)
2) SQL 语句统一存放到配置文件
3) SQL 语句变量和传入参数的映射以及动态 SQL
4) 动态 SQL 语句的处理
5) 对数据库操作结果的映射和结果缓存
-
MyBatis框架的缺点
- SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
-
什么是Mybatis的接口绑定,有什么好处
Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。
-
Mybatis在核心处理类
SqlSession
-
查询表名和返回实体Bean对象不一致,如何处理
映射键值对即可<result column="title" property="title" javaType="java.lang.String"/>
column:数据库中表的列名
property:实体Bean中的属性名
-
${} 和 #{}的区别
- ${}:简单字符串替换,把${}直接替换成变量的值,不做任何转换,这种是取值以后再去编译SQL语句。
- #{}:预编译处理,sql中的#{}替换成?,补全预编译语句,有效的防止Sql语句注入,这种取值是编译好SQL语句再取值。
- 总结:一般用#{}来进行列的代替
-
Mybatis工作原理
通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory。
SqlSessionFactory开启一个SqlSession,通过SqlSession实例获得Mapper对象并且运行Mapper映射的Sql语句。
完成数据库的CRUD操作和事务提交,关闭SqlSession。
-
当实体类中的属性名和表中的字段名不一样 ,怎么办
第1种:通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
第2种:通过 <resultMap>来映射字段名和实体类属性名的一一对应的关系。
-
通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao接口即Mapper接口。
接口的全限名,就是映射文件中的namespace的值;
接口的方法名,就是映射文件中Mapper的Statement的id值;
接口方法内的参数,就是传递给sql的参数。
Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。
在Mybatis中,每一个 <select>、<insert>、<update>、<delete>标签,都会被解析为一个MapperStatement对象。
Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。
-
在mapper中如何传递多个参数
1.DAO层的函数
public UserselectUser(String name, String area);
对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参
数一致往后加即可。
2.第二种:使用 @param 注解:
3.多个参数封装成map
-
Mybatis有哪些动态sql?
Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。
-
Mybatis Xml映射文件中的标签
<select>、<insert>、<update>、<delete>、<resultMap>、<parameterMap>、<sql>、<include><selectKey>
加上动态sql的9个标签,其中 <sql>为sql片段标签,通过 <include>标签引入sql片段, <selectKey>为不支持自增的主键生成策略标签
-
使用MyBatis的mapper接口调用时有哪些要求
- Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;
- Mapper.xml文件中的namespace即是mapper接口的类路径。
四、SpringBoot
-
什么是SpringBoot
SpringBoot基本上是 Spring框架的扩展,可以快速的创建Spring的应用程序。目的是简化Spring应用的创建和开发过程,
-
使用SpringBoot的好处
- 可以快速的构建项目。
- 对主流开发框架的无配置集成。
- 项目可独立运行,无须外部依赖Servlet容器。
- 简化依赖和配置,提高了开发、部署效率。
-
使用SpringBoot的缺点
缺点是集成度较高,使用过程中不太容易了解底层。
-
SpringBoot常用注解
- @SpringBootApplicatio:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。
- @Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全。
- @EnableAutoConfiguration 自动配置。
- @ComponentScan 组件扫描,可自动发现和装配一些Bean。
- @Component可配合CommandLineRunner使用,在程序启动后执行一些基础任务。
- @RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。
- @Autowired自动导入。
- @PathVariable获取参数。
- @JsonBackReference解决嵌套外链问题。
10. @RepositoryRestResourcepublic配合spring-boot-starter-data-rest使用。
SpringCloud
什么是SpringCloud
SpringCloud服务治理框架,专注于解决各个微服务之间的协调与配置, 为各个微服务之间提供,配置管理,服务发现,断路器,路由,事件总线等集成服务SpringCloud常用注解
- @Controller 控制层,里面有多个连接
- @Service 业务层,一般对于接口和实现
- @Qualifier 如果一个接口有多个实现,那么注入时候加上唯一标示
- @Repository 一般的dao层
- @Autowired 自动注入依赖
- @Resource bean的注入,同Autowired 有相同的功能。
说明:
共同点:@Resource和@Autowired都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。
不同点:
- @Resource是Java自己的注解,@Resource有两个属性是比较重要的,分是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
- @Autowired是spring的注解,是spring2.5版本引入的,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。
- @Component定义其它组件(比如访问外部服务的组件)
- @RequestMapping (value=’’,method={RequestMethod。GET或者POSt})绑定url
- @RequestParam (value=’’ required=false)绑定参数,将客户端请求中的参数值映射到相应方法的参数上;
10. @ModelAttribute 一般用于controller层,呗注解的方法会在所以mapping执行之前执行,并且可以绑定参数到Model model里面。
11. @Transactional (readOnly=true)注解式事务
12. @TransactionalEventListener用于配置事务的回调方法,可以在事务提交前、提交后、完成后以及回滚后几个阶段接受回调事件。
13. @Value(“${}”)可以注入properties里面的配置项
14. @ControllerAdvice 是spring3提供的新注解
15. @ExceptionHandler 如果在controller方法遇到异常,就会调用含有此注解的方法。
16. @InitBinder 一般用于controller 可以将所以form 讲所有传递进来的string 进行html编码,防止xss攻击,比如可以将字符串类型的日期转换成date类型
17. @EnableCaching 注解自动化配置合适的缓存管理器。
18. @EnableWebSecurity 注解开启spring security的功能,集成websercrityconfigureadapter。
19. @SringBootApplication相当于@configuration,@EnableAutoConfiguation @ComponentScan三个注解合用。
20. @EnableDiscoveryclient 注册应用为Eureka客户端应用,以获得服务发现的能力
21. @EnableAdminServer 使用admin监控应用。
22. @EnableEurekaClient配置本应用将使用服务注册和服务发现,注意:注册和发现用这个注解。
23. @EnableEurekaServer 启动一个服务注册中心
24. @EnableHystrix表示启动断路器,断路器依赖于服务注册和发现。
25. @HystrixCommand注解方法失败后,系统将西东切换到fallbackMethod方法执行。指定回调方法
26. @EnableAutoConfiguration spring boot自动配置,尝试根据你添加的jar依赖自动配置你的spring应用。
27. @ComponentScan 表示将该类自动发现并注册bean 可以自动收集所有的spring组件
28. @Comfiguration 相当于传统的xml配置文件
29. @Import 导入其他配置类
30. @ImportResource用来 加载xml配置文件
31. @FeignClient注解中的fallbank属性指定回调类
32. @RestController 返回json字符串的数据,直接可以编写RESTFul的接口;
33. @CrossOrigin 可以处理跨域请求,让你能访问不是一个域的文件;
34. @ApiOperation 首先@ApiOperation注解不是Spring自带的,它是是swagger里的注解@ApiOperation是用来构建Api文档的@ApiOperation(value = “接口说明”, httpMethod = “接口请求方式”, response = “接口返回参数类型”, notes = “接口发布说明”;
35. @SpringBootApplication 申明让spring boot自动给程序进行必要的配置,等价于以默认属性使用@Configuration,@EnableAutoConfiguration和@ComponentScan;
36. @RefreshScope 如果代码中需要动态刷新配置,在需要的类上加上该注解就行。但某些复杂的注入场景下,这个注解使用不当,配置可能仍然不动态刷新;
37. @FeignClient springboot调用外部接口:声明接口之后,在代码中通过@Resource注入之后即可使用。@FeignClient标签的常用属性如下:name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
38. url: url一般用于调试,可以手动指定@FeignClient调用的地址decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
39. configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contractfallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
40. fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码path: 定义当前FeignClient的统一前缀
41. @EnableFeignClients 开启Spring Cloud Feign的支持
42. @EnableCircuitBreaker 开启断路器功能
43. @LoadBalanced 开启客户端负载均衡
44. @WebAppConfiguration 开启Web 应用的配置,用于模拟ServletContext
45. @RibbonClient,这个注解用来为负载均衡客户端做一些自定义的配置,可以进一步配置或自定义从哪里获取服务端列表、负载均衡策略、Ping也就是服务鉴活策略等等
SpringCloud的核心组件有哪些
- 服务发现-Eureka:服务注册于发现。
- Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。整合了ribbon,具有负载均衡的能力;整合了Hystrix,具有熔断的能力
- 客服端负载均衡-Ribbon:实现负载均衡客户端,从一个服务的多台机器中选择一台。可以很好的控制http和tcp的一些行为。
- 断路器-Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。具备服务降级,服务熔断,依赖隔离,监控(Hystrix Dashboard)服务降级:
- 服务网关-Zuul:网关管理,由 Zuul 网关转发请求给对应的服务。
- 分布式配置-Config:配置管理。
SpringBoot和SpringCloud
- SpringBoot专注于快速方便的开发单个个体的微服务
- SpringCloud是关注全局的微服务协调整理治理框架,整合并管理各个微服务,为各个微服务之间提供,配置管理,服务发现,断路器,路由,事件总线等集成服务
- SpringBoot不依赖于SpringCloud,SpringCloud依赖于SpringBoot,属于依赖关系
- SpringBoot专注于快速,方便的开发单个的微服务个体,SpringCloud关注全局的服务治理框架
SpringCloud如何实现服务的注册
1.服务发布时,指定对应的服务名,将服务注册到 注册中心(eureka zookeeper)
2.注册中心加@EnableEurekaServer,服务用@EnableDiscoveryClient,然后用ribbon或feign进行服务直接的调用发现。
什么是服务熔断
所谓的服务熔断指的是某个服务故障或异常一起类似显示世界中的“保险丝"当某个异常条件被触发就直接熔断整个服务,而不是一直等到此服务超时。
什么是服务降级
服务熔断就是相当于我们电闸的保险丝,一旦发生服务雪崩的,就会熔断整个服务,通过维护一个自己的线程池,当线程达到阈值的时候就启动服务降级,如果其他请求继续访问就直接返回fallback的默认值
什么是服务雪崩
在复杂的分布式系统中,微服务之间的相互调用,有可能出现各种各样的原因导致服务的阻塞,在高并发场景下,服务的阻塞意味着线程的阻塞,导致当前线程不可用,服务器的线程全部阻塞,导致服务器崩溃,由于服务之间的调用关系是同步的,会对整个微服务系统造成服务雪崩
微服务的优点
- 每一个服务足够内聚,代码容易理解
- 开发效率提高,一个服务只做一件事
- 微服务能够被小团队单独开发
- 微服务是松耦合的,是有功能意义的服务
- 可以用不同的语言开发,面向接口编程
- 易于与第三方集成
- 微服务只是业务逻辑的代码,不会和HTML,CSS或者其他界面组合
开发中,两种开发模式
前后端分离
全栈工程师
- 可以灵活搭配,连接公共库/连接独立库
- Ribbon都是调用其他服务的,但方式不同。
- 启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients
- 服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
- 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。
微服务的缺点
- 分布式系统的负责性
- 多服务运维难度,随着服务的增加,运维的压力也在增大
- 系统部署依赖
- 服务间通信成本
- 数据一致性
- 系统集成测试
- 性能监控
Ribbon和Feign的区别
Struts2
Struts2的执行过程
第一部分:启动tomcat
加载应用—加载web.xml—创建struts2的核心控制(过滤器)的实例—加载struts.xml
第二部分:
客户浏览器—>tomcat服务器—>我们的应用—>web.xml—>找到过滤器—>依据配置文件,找到动作类—>实例化动作类(动作类是多例的)—>执行动作方法—>响应浏览器
Struts2的优点
- 在软件设计上Struts2的应用可以不依赖于Servlet API和struts API。 Struts2的这种设计属于无侵入式设计;
- 拦截器,实现如参数拦截注入等功能;
- 类型转换器,可以把特殊的请求参数转换成需要的类型;
- 多种表现层技术,如:JSP、freeMarker、Velocity等;
- Struts2的输入校验可以对指定某个方法进行校验;
- 提供了全局范围、包范围和Action范围的国际化资源文件管理实现
- Struts2框架的核心控制器是StrutsPrepareAndExecuteFilter。
- 作用:
Struts2框架的核心控制器是什么?它有什么作用?
负责拦截由<url-pattern></url-pattern>指定的所有用户请求,当用户请求到达时,该Filter会过滤用户的请求。默认情况下,如果用户请求的路径,不带后缀或者后缀以.action结尾,这时请求将被转入struts2框架处理,否则struts2框架将略过该请求的处理。可以通过常量"struts.action.extension"修改action的后缀
如:
<constant name="struts.action.extension" value="do"/>
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。
<constant name="struts.action.extension" value="do,go"/>
Struts2常量的修改方式
常量可以在struts.xml或struts.properties中配置,两种配置方式如下:
1)在struts.xml文件中配置常量
<constant name="struts.action.extension" value="do"/>
2)在struts.properties中配置常量(struts.properties文件放置在src下):
struts.action.extension=do
Struts2三个问题
1) Struts2的动作类是单例还是多例的?答:动作类是多例的
2) 当请求url以什么为后缀时进入Struts2内部?答:默认情况下是以.action或者什么都不写时。
3) 我们在使用Struts2开发时负责哪些?答:写配置文件,写动作类动作方法,写结果视图
为什么要使用Struts2
1) 在软件设计上Struts2的应用可以不依赖于Servlet API和struts API。Struts2的这种设计属于无侵入式设计;
2) 拦截器,实现如参数拦截注入等功能;
3) 类型转换器,可以把特殊的请求参数转换成需要的类型;
4) 多种表现层技术,如:JSP、freeMarker、Velocity等;
5) Struts2的输入校验可以对指定某个方法进行校验;
6) 提供了全局范围、包范围和Action范围的国际化资源文件管理实现
Shiro
什么是shiro
Shiro是java安全框架,提供了认证、授权、加密、会话管理、与web集成、缓存等功能。
Shiro的核心概念
- Subject:主体,当前用户(与当前应用交互的任何东西都Subject)的操作;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;
可以把Subject认为是一个门面;SecurityManager才是实际的执行者。
- SecurityManager:安全管理器;用于管理所有的Subject;是shiro的核心,
SecurityManager相当于spring mvc中的dispatcherServlet前端控制器。
- Realm:域,用于进行权限信息的验证;
shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;
可以把Realm看成DataSource,即安全数据源。
Authentication(身份验证) 和 Authorization(授权)
在shiro的用户权限认证过程中其通过两个方法来实现:
1、Authentication:是验证用户身份的过程。
2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
Shiro工作流程
也就是说对于我们而言,最简单的一个Shiro应用:
1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
shiro的优点
- 简单的身份验证,支持多种数据源
- 对角色的简单授权,支持细粒度的授权(方法)
- 支持一级缓存,以提升应用程序的性能
- 内置基于POJO的企业会话管理,适用于web及非web环境
- 非常简单的API加密
- 不跟任何框架绑定,可以独立运行
- @RequiresAuthentication : 表示当前Subject已经通过login进行了身份验证;即 Subject.isAuthenticated() 返回 true
- @RequiresUser : 表示当前Subject 已经身份验证或者通过记住我登录的
- @RequiresGuest : 表示当前Subject没有身份验证或通过记住我登陆过,即是游客身份
- @RequiresRoles(value = { “admin”, “user” }, logical = Logical.AND) : 表示当前 Subject 需要角色 admin和user
- @RequiresPermissions(value = { “user:a”, “user:b” }, logical = Logical.OR) : 表示当前 Subject 需要权限 user:a 或 user:b
shiro 注解
Shiro 如何自实现认证
Shiro的认证过程由 Realm 执行,
SecurityManager会调用Realm 的 getAuthenticationInfo(AuthenticationToken token) 方法. 实际开发中, 通常提供 AuthenticatingRealm 的实现类, 并在该实现类中提供 doGetAuthenticationInfo(AuthenticationToken token)方法的具体实现
如何实现自实现授权
实际开发中, 通常提供 org.apache.shiro.realm.AuthorizingRealm 的实现类,
并提供 doGetAuthorizationInfo(PrincipalCollection principals) 方法的具体实现
Session Manager 会话管理
什么是是粗颗粒和细颗粒
粗颗粒权限:对资源类型的管理称为粗颗粒度权限管理,即只控制到菜单、按钮、方法
细颗粒权限:对资源实例的控制称为细颗粒度权限管理,即控制到数据级别的权限
Sentinel
Sentinel是什么?
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。
类似Sentinel的产品你知道有什么?
hystrix-一代微服务产品
Sentinel是如何对请求进行限流的?
基于sentinel依赖提供的拦截器
Sentinel 默认的限流算法是什么?
滑动窗口算法
Sentinel与Hystrix的区别
Seata
什么是Seata
Seata是阿里巴巴推出的一款用来解决分布式事务问题的框架
分布式事务
本质上来说,分布式事务就是为了保证不同的数据库的数据一致性。
Redis
什么是redis
Redis 是一个基于内存的非关系型高性能key-value数据库
使用Redis有哪些好处
- 性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
- 单进程单线程,是线程安全的。
- 丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
- 支持数据持久化。
- 可以将内存中数据保存在磁盘中,重启时加载。
- 主从复制,哨兵,高可用。
- 可以用作分布式锁。
- 可以作为消息中间件使用,支持发布订阅。
- RDB:快照形式的保存策略,是直接把内存中的数据定时保存到一个二进制 dump 的文件中。Redis 默认是快照 RDB 的持久化方式。
- AOF:把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。
Redis 的持久化策略有两种
当 Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存。
RDB 是怎么工作的
- 默认 Redis 是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件 dump.rdb。
- 工作原理:当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write。
RDB 的优点
这种文件非常适合用于备份:比如,你可以在最近的 24 小时内,每小时备份一次,并且在每个月的每一天也备份一个 RDB 文件。
这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适合灾难恢复。
RDB 的缺点
如果你需要尽量避免在服务器故障时丢失数据,那么RDB不合适你
AOF优点
AOF 的优点是会让 Redis 变得非常耐久。可以设置不同的 Fsync 策略,AOF的默认策略是每秒钟 Fsync 一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。
AOF缺点
对于相同的数据集来说,AOF 的文件体积通常要大于 RDB 文件的体积。根据所使用的 Fsync 策略,AOF 的速度可能会慢于 RDB。
Redis支持的数据类型
- String
String 是 Redis 最基本的类型。String 类型的值最大能存储 512M。
- List
List 列表是简单的字符串列表,按照插入顺序排序。
- Set
无序的字符串集合,不存在重复的元素
常用命令:sdd、spop、smembers、sunion 等。
- sorted set
和 Set一样是String类型元素的有序集合。
常用命令:zadd、zrange、zrem、zcard 等。
- Hash
Hash是一个键值(key-value)的集合。
Hash 特别适合存储对象。常用命令:hget,hset,hgetall 等。
Redis是单进程单线程的
Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销
Redis的回收策略
- volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据
- 会话缓存(Session Cache)
- 全页缓存(FPC)
- 队列
- 排行榜/计数器
- 发布/订阅
Redis 最适合的场景
Redis 和 Memcached 的区别
原因有如下四点:
- 存储方式上:Memcache 会把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis 有部分数据存在硬盘上,这样能保证数据的持久性。
- 数据支持类型上:Memcache 对数据类型的支持简单,只支持简单的 key-value,,而 Redis 支持五种数据类型。
- 使用底层模型不同:它们之间底层实现方式以及与客户端之间通信的应用协议不一样。Redis 直接自己构建了 VM 机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
- Value 的大小:Redis 可以达到 1GB,而 Memcache 只有 1MB。
- 原子性(Atomicity):数据库的操作的最小的单位就是事务,保证操作的全部完成或全部失败。
- 一致性(Consistency):一个事务中的多个操作的结果数据是一致的,同时成功和同时失败
- 隔离性(Isolation):多个事务之间的操作互不影响,比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
- 持久性(Durability):当一个事务提交后,更新操作才持久化到磁盘上
Mysql
事务的四大特性ACID
在不考虑隔离性的前提下会产生哪些影响?
模拟两个事务A事务 B事务
- 脏读(Dirty read):B事务读到了A事务尚未提交的事务
- 不可重复读(Nonrepeatable read):重点在修改;A事务中两次读取的数据的内容不一致
- 虚读/幻读(Phantom reads):重点在新增或删除;A事务中两次读取的数据的数量不一致
事务的隔离级别
通过设置数据库的隔离级别 解决上述的问题:
读未提交(read uncommitted):读取尚未提交的事务,什么都不能解决
不可重复读(read committed):读取已经提交的内容,可以解决脏读
可重复读(repeatable read):重复读,可以解决脏读和不可重复读
串行化(serializable):串行化,可以解决所有
事务隔离级别 |
脏读 |
不可重复读 |
幻读 |
读未提交(read-uncommitted) |
是 |
是 |
是 |
不可重复读(read-committed) |
否 |
是 |
是 |
可重复读(repeatable-read) |
否 |
否 |
是 |
串行化(serializable) |
否 |
否 |
否 |
数据库默认的隔离级别
mysql的默认隔离级别:repeatable read
oracle的默认的隔离级别:read committed
连接池内部的原理
连接池一创建就初始化一些Connection资源
当使用Connection时不是创建而是从池子中获取一个资源
当资源使用完毕不是将该资源销毁而是将资源在归还给池子
having与where的区别
having是在分组后对数据进行过滤.
where是在分组前对数据进行过滤
having后面可以使用分组函数(统计函数)
where后面不可以使用分组函数。
Maven
什么是maven
Maven是Apache下的一个开源项目,它是一个项目管理工具,它用于对java项目进行项目构建、依赖管理及项目信息管理。
为什么选用 Maven 进行构建
- 首先,Maven 是一个优秀的项目构建工具。使用maven,可以很方便的对项目进行分模块构建,这样在开发和测试打包部署时,效率会提高很多。
- 其次,Maven 可以进行依赖的管理。使用 Maven ,可以将不同系统的依赖进行统一管理,并且可以进行依赖之间的传递和继承。
Maven 常用命令
- mvn archetype:create :创建 Maven 项目。
- mvn compile :编译源代码。
- mvn deploy :发布项目。
- mvn test-compile :编译测试源代码。
- mvn test :运行应用程序中的单元测试。
- mvn site :生成项目相关信息的网站。
- mvn clean :清除项目目录中的生成结果。
- mvn package :根据项目生成的 jar/war 等。
- mvn install :在本地 Repository 中安装 jar 。
- mvn eclipse:eclipse :生成 Eclipse 项目文件。
- mvn jetty:run 启动 Jetty 服务。
- mvn tomcat:run :启动 Tomcat 服务。
- mvn clean package -Dmaven.test.skip=true :清除以前的包后重新打包,跳过测试类。
用到最多的命令:
- mvn eclipse:clean :清除 Project 中以前的编译的东西,重新再来。
- mvn eclipse:eclipse :开始编译 Maven 的 Project 。
- mvn clean package :清除以前的包后重新打包。
- 简化了项目依赖管理。
- 易于上手,对于新手可能一个 mvn clean package 命令就可能满足我们的工作。
- 便于与持续集成工具(Jenkins)整合。
- 便于项目升级,无论是项目本身升级还是项目使用的依赖升级。
- 有助于多模块项目的开发,一个模块开发好后,发布到仓库,依赖该模块时可以直接从仓库更新,而不用自己去编译。
- Maven 有很多插件,便于功能扩展,比如生产站点,自动发布版本等。
- Maven 是一个庞大的构建系统,学习难度大。
- Maven 采用约定优于配置的策略(convention over configuration),虽然上手容易,但是一旦出了问题,难于调试。。
- 当依赖很多时,m2eclipse 老是搞得 Eclipse 很卡。
- 中国的网络环境差,很多 repository 无法访问,比如 Google Code、 JBoss 仓库无法访问等。
Maven优点
Maven缺点
Maven生命周期
清理生命周期:运行mvn clean将调用清理生命周期。
默认生命周期:是一个软件应用程序构建过程的总体模型。
站点生命周期:为一个或者一组项目生成项目文档和报告,使用较少。
Maven主要两个功能
- 项目构建
- 依赖管理
Maven构建过程
Git
什么是Git
Git 是分布式版本控制系统(DVCS)。它可以跟踪文件的更改,版本的恢复。
Git常用命令
新增文件的命令:git add file或者git add .
提交文件的命令:git commit –m “”或者git commit –a “”
查看工作区状况:git status –s
拉取合并远程分支的操作:git fetch/git merge或者git pull
查看提交记录命令:git reflog
Git与Svn的区别
都是代码版本管理系统;
SVN必须先Update才能Commit,忘记了合并时就会出现一些错误,git还是比较少的出现这种情况
- Git是分布式版本控制系统;内容按元数据方式存储;没有全局版本号;
- SVN 是集中式版本控制系统;内容按文件方式存储;有全局版本号;
- git fetch的意思是将远程主机的最新内容拉到本地,用户再检查无误后再决定是否合并到工作本地分支中
- git pull 是将远程主机中的最新内容拉取下来后直接合并,即:git pull = git fetch+git merge,这样可能会产生冲突,需要手动解决。
git fetch与git pull区别
Jdk1.8新特性
常用的是Lambda表达式,集合的Stream,foreach、分组、排序等
Linux操作系统
常见操作命令
Mkdir:创建目录
Touch:创建文件
Ll:查看当前目录所有文件和目录列表
Ls -a:查看当前目录下所有文件和目录列表,包含隐藏的
查看文件内容:
vi 文件名 #编辑方式查看,可修改
cat 文件名 #显示全部文件内容
more 文件名 #分页显示文件内容
less 文件名 #与 more 相似,更好的是可以往前翻页
tail 文件名 #仅查看尾部,还可以指定行数
head 文件名 #仅查看头部,还可以指定行数
Cd:去某个目录
Cp:复制
Mv:移动
Rm:删除
Grep:通道
Tail 查看进程
Kill -9:强制杀掉进程
Find:查找
History:查看用过的命令列表
Du: 显示目录或文件的大小
df 显示每个<文件>所在的文件系统的信息,默认是显示所有文件系统。
ifconfig:查看 ip 地址及接口信息
nginx
什么是Nginx
Nginx是一个 轻量级/高性能的反向代理Web服务器,他实现非常高效的反向代理、负载平衡,他可以处理2-3万并发连接数,官方监测能支持5万并发
为什么要用Nginx
- 占内存小,可实现高并发连接,处理响应快
- 可实现http服务器、虚拟主机、方向代理、负载均衡
- Nginx配置简单
- 可以不暴露正式的服务器IP地址
- 支持很好的访问静态文件;
Nginx怎么处理请求的
nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址
什么是正向代理和反向代理
- 正向代理就是一个人发送一个请求直接就到达了目标的服务器
- 反方代理就是请求统一被Nginx接收,nginx反向代理服务器接收到之后,按照一定的规 则分发给了后端的业务处理服务器进行处理了
反向代理服务器的优点是什么
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用web托管服务时。
Nginx应用场景
- http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
- 虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。
- 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。
- nginx 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。
Nginx目录结构有哪些
Nginx配置文件nginx.conf有哪些属性模块
Nginx 常用命令
启动 nginx 。
停止 nginx -s stop 或 nginx -s quit 。
重载配置 ./sbin/nginx -s reload(平滑重启) 或 service nginx reload 。
重载指定配置文件 .nginx -c /usr/local/nginx/conf/nginx.conf 。
查看 nginx 版本 nginx -v 。
检查配置文件是否正确 nginx -t 。
显示帮助信息 nginx -h 。
负载均衡
负载均衡即是代理服务器将接收的请求均衡的分发到各服务器中,负载均衡主要解决网络拥塞问题,提高服务器响应速度,服务就近提供,达到更好的访问质量,减少后台服务器大并发压力
集合
Vector 和 ArrayList
ArrayList替代了Vector
ArrayList:线程不安全,效率高,底层是数组
Vector:线程安全,效率低。底层是数组
HashMap 和 Hashtable
HashMap替代了Hashtable
HashMap:线程不安全,效率高,允许有null键和null值
Hashtable:线程安全,效率低。不允许有null值和null键
Collection与Collections的区别
要点:长得像,但是关系不大
Collection:是单列集合的顶层接口,有子接口List和Set。JDK 1.5之前是 之后不是,之后
Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法,都是静态方法
Map集合和Collection集合的区别
Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对;
Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍(11.11);
List,Set,Map 是否都继承的Map接口
List,Set继承了Collection接口
Map接口本身就是一个顶层接口
Java集合类框架的基本接口有哪些
- Collection:代表一组对象,每一个对象都是它的子元素。
- Set:不包含重复元素的Collection。
- List:有顺序的collection,并且可以包含重复元素。
- Map:可以把键(key)映射到值(value)的对象,键不能重复。
各集合框架之间的关联
(1):ArrayList(数组结构)和 LinkedList(链表结构)的共性:
- 都有索引
- 都有增删改查的功能
- 都可以存null值,并且可以是多个null元素
- 都可以存重复元素
- 添加顺序和取出顺序一致
(2):HashSet(哈希表结构)的特点:
- 存入与取出顺序不一致
- 有增删改的功能,但是都没有查的功能
- HashSet(特殊)可以添加null,但是只多只能添加一个
(3):TreeSet(二叉树结构)的特点:
- 不能添加 null 元素,因为 null元素无法比较大小
- 有增删改的功能,但是都没有查的功能
- 取出是排序排好的
(4):List(接口)和 set(接口)的共性:
- 都有增删改的功能
- 都是collection的子类
(5):collection(集合框架)和 Map(接口)共性:
- 都继承java.util.lang
isEmpty和isBlank与isNoneEmpty和isNoneBlank的区别
@NotEmpty、@NotBlank、@NotNull的区别
@NotEmpty 用在集合类上面(此集合不能为null,且Size>0)
@NotBlank 用在String上面(只用于String,不能为null且trim()之后size>0)
@NotNull 用在基本类型上(不能为null,但可以为empty,没有Size的约束)
使用详见:框架/24hibernate/Spring Validation(使用Hibernate Validator)
IO流
close()和flush()的区别
close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
多线程
线程中的stop()为什么废弃
可能引起死锁,取而代之的是Interrupt
多线程有几种实现方案,分别是哪几种?
两种方式:
继承Thread类
实现Runnable接口
扩展一种:
实现Callable接口。这个得和线程池结合。
多线程同步的方式
同步代码块
同步方法
lock
启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用,不会创建线程
start():启动线程,并由JVM自动调用run()方法,创建线程
sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。不再抢占CPU
wait():可以不指定时间,也可以指定时间;释放锁。不再抢占CPU
为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
线程的生命周期图
新建 -- 就绪 -- 运行 -- 死亡
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
建议:画图解释。
线程的生命周期(参照 线程生命周期图解.bmp)
a) 新建:创建线程对象
b) 就绪:有执行资格,没有执行权
c) 运行:有执行资格,有执行权
d) 阻塞:由于一些操作让程序处于该状态,没有执行资格,没有执行权,而另一些操作可以把他激活,激活后处于就粗状态
e) 死亡:线程随想变成垃圾,等待被回收
线程的基本概念、基本状态
a) 线程概念,有时称为轻量级进程,是CPU使用的基本单元;它由线程ID、程序计数器、寄存器集合和堆栈组成。
b) 线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态。
线程与进程的区别
a) 线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
b) 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
c) 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
d) 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。
e) 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
ES
什么是Elasticsearch:
Elasticsearch 是基于 Lucene 的 Restful 的分布式实时全文搜索引擎,每个字段都被索引并可被搜索,可以快速存储、搜索、分析海量的数据。
Elasticsearch 的基本概念:
- index 索引:索引类似于mysql 中的数据库,Elasticesearch 中的索引是存在数据的地方,包含了一堆有相似结构的文档数据。
- type 类型:类型是用来定义数据结构,可以认为是 mysql 中的一张表,type 是 index 中的一个逻辑数据分类
- document 文档:类似于 MySQL 中的一行,不同之处在于 ES 中的每个文档可以有不同的字段,但是对于通用字段应该具有相同的数据类型,文档是es中的最小数据单元,可以认为一个文档就是一条记录。
- Field 字段:Field是Elasticsearch的最小单位,一个document里面有多个field
- shard 分片:单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。
- replica 副本:任何一个服务器随时可能故障或宕机,此时 shard 可能会丢失,因此可以为每个 shard 创建多个 replica 副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个 shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。
Nacos
什么是nacos
Nacos是服务注册配置中心,支持动态服务发现、服务配置、服务健康检测和微服务管理;
微服务间远程交互的过程
先去注册中心查询服务的服务器地址
调用方给对方发送http请求
常见的注册中心
- Eureka(原生,2.0遇到性能瓶颈,停止维护)
- Zookeeper(支持,专业的独立产品。例如:dubbo)
- Consul(原生,GO语言开发)
- Nacos
为什么要用nacos
相对于SpringCloud Eureka来说,Nacos更强大。
Nacos可以与Spring, Spring Boot, Spring Cloud集成,并能代替Spring Cloud Eureka+Spring Cloud Config。
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
Alibaba Nacos和Spring Cloud Netflix的区别
- Nacos是Spring Cloud Alibaba的注册中心,是一个软件,直接运行,还可以当做配置中心使用;
- Netflix的配置中心是Eureka,Eureka不是一个软件,是一个框架,需要我们创建项目添加依赖,编写配置才能运行,而且只有配置中心的功能。
什么是网关
网关是当前微服务项目请求的唯一入口,可以统一管理用户身份和权限认证、监控和记录网站的访问数据和状态。
如果没有网关,各种客户端请求到当前项目的各个微服务会变得非常混乱,不好管理,容易有安全漏洞.
RabbitMQ
RabbitMQ是什么
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)
RabbitMQ特点
- 可靠性: RabbitMQ使用一些机制来保证可靠性, 如持久化、传输确认及发布确认等。
- 灵活的路由 : 在消息进入队列之前,通过交换器来路由消息。对于典型的路由功能, RabbitMQ 己经提供了一些内置的交换器来实现。针对更复杂的路由功能,可以将多个 交换器绑定在一起, 也可以通过插件机制来实现自己的交换器。
- 扩展性: 多个RabbitMQ节点可以组成一个集群,也可以根据实际业务情况动态地扩展 集群中节点。
- 高可用性 : 队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下队 列仍然可用。
- 多种协议: RabbitMQ除了原生支持AMQP协议,还支持STOMP, MQTT等多种消息 中间件协议。
- 多语言客户端 :RabbitMQ 几乎支持所有常用语言,比如 Java、 Python、 Ruby、 PHP、 C#、 JavaScript 等。
- 管理界面 : RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息、集 群中的节点等。
- 令插件机制 : RabbitMQ 提供了许多插件 , 以实现从多方面进行扩展,当然也可以编写自 己的插件。
生产者Producer和消费者Consumer
a) 生产者
消息生产者,就是投递消息的一方。
消息一般包含两个部分:消息体(payload)和标签(Label)。
b) 消费者
消费消息,也就是接收消息的一方。
消费者连接到RabbitMQ服务器,并订阅到队列上。消费消息时只消费消息体,丢弃标签。
RabbitMQ 包括哪些要素
- 生产者 :消息的创建者,发送到RabbitMQ
- 消费者 :连接到RabbitMQ,订阅到队列上,消费消息,持续订阅(basicConsumer)和单条订阅(basicGet)
- 消息 :包含有效载荷和标签,有效载荷指要传输的数据,标签描述了有效载荷,并且RabbitMQ用它来决定谁获得消息,消费者只能拿到有效载荷,并不知道生产者是谁。
为什么需要消息队列
消息对列可以用于异步处理、服务解耦、流量控制(削峰)
什么是死信队列
DLX,全称为 Dead-Letter-Exchange,死信交换器,死信邮箱。当消息在一个队列中变成死信 (dead message) 之后,它能被重新被发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称之为死信队列。
导致的死信的几种原因
- 消息被拒(Basic.Reject /Basic.Nack) 且 requeue = false。
- 消息TTL过期。
- 队列满了,无法再添加。
什么是延迟队列
存储对应的延迟消息,指当消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
RabbitMQ中消息可能有的几种状态
alpha: 消息内容(包括消息体、属性和 headers) 和消息索引都存储在内存中 。
beta: 消息内容保存在磁盘中,消息索引保存在内存中。
gamma: 消息内容保存在磁盘中,消息索引在磁盘和内存中都有 。
delta: 消息内容和索引都在磁盘中 。
应用场景
- 接口之间耦合比较严重
- 面对大流量并发时,容易被冲垮
- 存在性能问题
- Client发送消息给MQ
- MQ将消息持久化后,发送Ack消息给Client,此处有可能因为网络问题导致Ack消息无法发送到Client,那么Client在等待超时后,会重传消息;
- Client收到Ack消息后,认为消息已经投递成功。
- MQ将消息push给Client(或Client来pull消息)
- Client得到消息并做完业务逻辑
- Client发送Ack消息给MQ,通知MQ删除该消息,此处有可能因为网络问题导致Ack失败,那么Client会重复消息,这里就引出消费幂等的问题;
- MQ将已消费的消息删除
生产者如何将消息可靠投递到MQ
MQ如何将消息可靠投递到消费者
ActiveMQ
什么是是ActiveMQ
消息中间件。可以在分布式系统的不同服务之间进行消息的发送和接收
ActiveMQ作用
- 解决不同系统间的通讯,异步操作数据等
- 监听商品添加消息,接收消息,将对应的商品信息同步到索引库
- 每次添加完商品并将同步商品到索引库如果,如果直接同步数据库,当数据库很大的时候,会影响服务器性能,这时我们,就使用ActiveMQ消息中间件,后台添加完消息后,搜索服务器发送一个消息【商品id】,并将接收到的商品id在数据库中查找跟商品id有关的信息,吧信息添加到索引库中
activemq的几种通信方式
点到点形式和发布订阅模式
Queue和Topic的区别
a) 点对点(point-to-point,简称PTP)Queue消息传递模型:
在该消息传递模型下,一个消息生产者向消息服务器端一个特定的队列发送消息,一个消费者从该队列中读取消息。在这种模型下,消息生产者知道消息消费者的队列并直接将消息发送到消息消费者的队列。这种模型的特点是能够保证数据安全
b) 发布/订阅(publish/subscribe,简称pub/sub)Topic消息传递模型:
在该消息传递模型下,一个消息发布者向一个特定的消息主题发布消息,0或多个对此消息主题感兴趣的并且处于活动状态的消息订阅者或者建立了持久订阅的消息订阅者才可以接收到所发布的消息。可能造成数据丢失
ActiveMQ【JMS的同步与异步】发送消息的方式有哪些
- 同步方式
两个通信应用服务之间必须要进行同步,两个服务之间必须都是正常运行的。发送程序和接收程序都必须一直处于运行状态,并且随时做好相互通信的准备。
发送程序首先向接收程序发起一个请求,称之为发送消息,发送程序紧接着就会堵塞当前自身的进程,不与其他应用进行任何的通信以及交互,等待接收程序的响应,待发送消息得到接收程序的返回消息之后会继续向下运行,进行下一步的业务处理。
- 异步方式
两个通信应用之间可以不用同时在线等待,任何一方只需各自处理自己的业务,比如发送方发送消息以后不用登录接收方的响应,可以接着处理其他的任务。也就是说发送方和接收方都是相互独立存在的,发送方只管方,接收方只能接收,无须去等待对方的响应。
Java中JMS就是典型的异步消息处理机制,JMS消息有两种类型:点对点、发布/订阅
Zookerper/Dubbo
dubbo和zookeeper是配对使用
什么是Zookeeper
服务注册中心
什么是dubbo
Dubbo是阿里巴巴开发用来治理服务中间件。
Dubbo就是资源调度和治理中心的管理工具(war)
为什么要使用Dubbo
使用zookeeper和dubbo的目的就是提高并发(10000+以上)
组合使用流程
项目启动时服务通过Dubbo将服务注册到Zookeeper服务注册中心中
调用者通过dubbo引用zookeeper注册中心的服务
Thymeleaf
thymeleaf是什么
thymeleaf是模板引擎,常见的还有Freemarker, Velocity,Jsp。
引入提示
页面引入thymeleaf命名空间
语法
使用th,获取值用的是${}和@{}和*{}
框架区别
SpringMVC和Struts2的区别
第一种描述:
1) 从实现机制来说
struts2:前端控制器底层是基于过滤器实现的
springmvc:前端控制器的底层使用的是servlet
总结:更底层的速度快、效率高
2) 从运行效率来说
struts2:是多例的
springmvc:是单例的
总结:单例的执行速度要比多例的执行速度快
3) 从封装参数来说
struts2:是基于属性封装的
springmvc:是基于方法进行封装的
基于方法封装的好处:方法的参数是局部变量,方法一结束,变量内存空间就会被释放了,更节约资源,效率更高
第二种描述:
入口不同:
Struts2:filter过滤器
SpringMvc:一个Servlet即前端控制器
开发方式不同:
Struts2:基于类开发,传递参数通过类的属性,只能设置为多例
SpringMvc:基于方法开发(一个url对应一个方法),请求参数传递到方法形参,可以为单例也可以为多例(建议单例)
请求方式不同:
Struts2:值栈村塾请求和响应的数据,通过OGNL存取数据
SpringMvc:通过参数解析器将request请求内容解析,给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面,jsp视图解析器默认使用的是jstl。
实现机制
struts2:前端控制器底层是基于过滤器实现的
springmvc:前端控制器的底层使用的是servlet
总结:更底层的速度快、效率高
运行效率
struts2:是多例的
springmvc:是单例的
总结:单例的执行速度要比多例的执行速度快
封装参数
struts2:是基于属性封装的
springmvc:是基于方法进行封装的
总结:基于方法封装的好处:方法的参数是局部变量,方法一结束,变量内存空间就会被
释放了,更节约资源,效率更高
Mybatis和Hibernate的区别
Mybatis和hibernate都是对jdbc封装:
- Hibernate
优点:完全面向对象,不需要我们自己写sql语句 数据库迁移,hibernate使用面向对象开发,只需要修改方言
缺点:语句不规范,不易挑错。
- Mybatis:
mybatis简化程序员的工作,把精力放在sql语句上面。
适合开发复杂业务。 对项目维护,调优比较容易。
尤其是需求变化特别快的项目都采用mybatis来开发(互联网项目)
执行流程
SpringMVC的执行流程
第一种描述:
1) 用户发送请求
2) springmvc的前端控制器DispatcherServlet(在web.xml中配置)会接接收请求数据
3) 将请求发送给处理器映射器(HandlerMapping)(在springmvc.xml中配置),处理器映射器会寻找执行类controller,并将结果再次返回给前端控制器(返回的结果是一个chain(链){链中包含拦截器... controller对象 拦截器... })
4) 前端控制器拿到controller对象后会将对象转发给处理器适配器(HandlerAdpater)(在springmvc.xml中配置)
5) 处理器适配器负责调用controller(再调用服务层和持久层)方法,并返回视图数据(ModelAndView)
6) 处理器适配器会将ModelAndView再次返回给前端控制器
7) 前端控制器会将modelandview再次转发给视图解析器(ViewResolver)(在springmvc.xml中配置),视图解析器会解析出正真的物理视图(view),得到model数据,视图解析器会将model再次返回给前端控制器
8) 前端控制前会将model数据发给视图渲染器(view),视图渲染器会将渲染结果(页面)返回给前端控制器
9) 前端控制器会将页面响应给用户
第二种描述:
1) spring mvc请所有的请求都交给DispatcherServlet,它会委托其他应用系统的其他功能模块对请求进行处理。
2) DispatcherServlet查询一个或多个HandlerMapping,会找到处理请求的Controller.
3) DispatcherServlet把请求提交给目标Controller.
4) Controller进行业务逻辑处理后,会返回一个ModelAndView.
5) DispatcherServlet查询一个多个ViewResolvet视图解析器,找到ViewResolvet对象指定的视图对象。
6) 视图对象负责渲染饭后客户端。
Struts2的执行流程
1) tomcat启动加载web.xml
2) 实例化并初始化过滤器StrutsPrepareAndExecuteFilter
3) 用户发送求情到tomcat,tomcat将请求转发到过滤器
4) 过滤器拦截动作类的请求名称,并从struts.xml配置文件中查找
5) 找到后实例化动作类
6) 调用相应的动作方法,方法有返回值
7) 根据返回值找到name属性对应的返回值
8) 找到页面
9) 响应浏览器,显示结构
Mybatis的执行流程
1) 加载mybatis的全局配置文件sqlMapConfig.xml(数据源、事物等),全局配置文件中包含映射配置文件(封装sql语句)
2) 创建sqlsessionfactory工厂,生产sqlsession
3) sqlsession提供了一些接口(包含增、删、改、查)
4) 执行mybatis执行器Excutor(是一个类),封装一个执行方法MappedStatement
5) MappedStatement会执行传入的生sql语句对象,并输出参数
6) 查询数据库
Hibernate的执行流程
就是让程序员通过操作对象的方式来操作数据库中的表。
实体与表的映射(对象关系映射)
目的就是让程序员用操作对象的方式来操作数据库中的数据库
Servlet
Servlet的声明周期
何时创建Servlet对象:
默认第一次访问时创建Servlet对象,会将servlet放置到web容器的内存中,等待为后面的访问服务;某一个Servlet对象只有一个执行init方法
何时销毁Servlet对象:
服务器关闭或web应从服务器中移除Servlet销毁,销毁时会执行destory方法
必然执行的方法: service方法,每次客户端请求都会执行一次。
Servlet的执行过程
第一部分:启动tomcat
加载应用——加载web.xml配置文件。
第二部分:应用运行
客户浏览器—>tomca服务器—>我们的应用—>web.xml—>找到Servlet—>执service方法—>响应浏览器
servlet的三大组件:
servlet 技术
Listener 技术
Filter 技术
Cookies和Session
Cookie和Session的区别
cookie:客户端回话,默认一次请求,相对不安全
session:服务气端回话,默认一次回话,相对安全
Session的声明周期
session是服务器端回话技术
session域对象的域范围是一次会话
创建:第一次调用request.getSession()
销毁:
1)服务器关闭 session销毁
2)session超时 默认30分钟(最后一次操作该站点后的30分钟)
3)手动销毁session, session.invalidate();
cookie的声明周期
数据格式是:key : value
默认是一次请求,在请求结束后cookie会自动消失
也可以设置最大化持久化时间(单位:秒):
可以是0,删除持久化cookie
可以是-1,代表浏览器关闭后失效
Html
javaScript的三种跳出式消息提醒命令
警告:alert
确认:confirm
信息输入:prompt
JavaEE基础
&和&&的区别(|和||)
&与&&最终结果一样。
&&具有短路效果。左边是false,右边不执行。
|与||最终结果一样。
||具有短路效果。左边是true,右边不执行。
注意:开发中常用的逻辑运算符:&&,||,!
==和equals()的区别
==
比较基本类型:比较的是值是否相同
比较引用类型:比较的是地址值是否相同
equals()
只能比较引用类型。
默认情况下,比较的是地址值是否相同,但是,我们可以根据自己的需要重写该方法。
转发和重定向的区别
转发:一次请求、地址栏不发生变化、服务器端操作、域中数据不会丢失
重定向:两次请求、地址栏反生变化、客户端操作、请求域中的数据丢失
拦截器(Interceptor)和过滤器(Filter)的区别
共同点:
都是单例的。
都可以拦截请求。
都是访问资源之前和之后都会经过。
区别:
- 拦截器是基于java反射机制的,而过滤器是基于函数回调的。
- 过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
- 过滤器是针对整个web应用的。
- 拦截器只能是针对struts2的。如果不用struts2,则没有拦截器。而且如果访问的不是struts2默认拦截的资源,则不会经过拦截器。(默认情况下,如果不是以.action为后缀或者没有后缀,根本不会进入struts2的核心内部)
- 在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。
- 但是,过滤器比Servlet功能更加强大,Servlet能做的过滤器都能实现,并且还多了一个放行的功能。
GET与POST的区别
get是从服务器上获取数据,post是向服务器传送数据。
get是把参数数据队列加到提交表单的action属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。
post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML header内一起传送到ACTION属性所指的URL地址,用户看不到这个过程。
对于get方式,服务器端用Request.QueryString获取变量的值,
对于post方式,服务器端用Request.Form获取提交的数据。
get传送的数据量较小,不能大于2KB。
post传送的数据量较大,一般被默认为不受限制。
但理论上,IIS4中最大量为80KB,IIS5中为100KB。
get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
this和super的区别
this:代表当前类的对象引用
super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
场景:
成员变量:
this.成员变量
super.成员变量
构造方法:
this(...)
super(...)
成员方法:
this.成员方法
super.成员方法
final、finally和finalize的区别
final:最终的意思,可以修饰类,成员变量,成员方法
修饰类,类不能被继承
修饰变量,变量是常量
修饰方法,方法不能被重写
finally:是异常处理的一部分,用于释放资源。
一般来说,代码肯定会执行,特殊情况:在执行到finally之前jvm退出了
finalize:是Object类的一个方法,用于垃圾回收
throws和throw的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
响应的状态码
- 100 ~ 客户必须继续发出请求
- 101 ~ 客户要求服务器根据请求转换HTTP协议版本
- 200 ~ 交易成功
- 201 ~ 提示知道新文件的URL
- 202 ~ 接受和处理、但处理未完成
- 203 ~ 返回信息不确定或不完整
- 204 ~ 请求收到,但返回信息为空
- 205 ~ 服务器完成了请求,用户代理必须复位当前已经浏览过的文件
- 206 ~ 服务器已经完成了部分用户的GET请求
10. 300 ~ 请求的资源可在多处得到
11. 301 ~ 删除请求数据
12. 302 ~ 在其他地址发现了请求数据
13. 303 ~ 建议客户访问其他URL或访问方式
14. 304 ~ 客户端已经执行了GET,但文件未变化
15. 305 ~ 请求的资源必须从服务器指定的地址得到
16. 306 ~ 前一版本HTTP中使用的代码,现行版本中不再使用
17. 307 ~ 申明请求的资源临时性删除
18. 400 ~ 错误请求,如语法错误
19. 401 ~ 请求授权失败
20. 402 ~ 保留有效ChargeTo头响应
21. 403 ~ 请求不允许
22. 404 ~ 没有发现文件、查询或URl
23. 405 ~ 用户在Request-Line字段定义的方法不允许
24. 406 ~ 根据用户发送的Accept拖,请求资源不可访问
25. 407 ~ 类似401,用户必须首先在代理服务器上得到授权
26. 408 ~ 客户端没有在用户指定的饿时间内完成请求
27. 409 ~ 对当前资源状态,请求不能完成
28. 410 ~ 服务器上不再有此资源且无进一步的参考地址
29. 411 ~ 服务器拒绝用户定义的Content-Length属性请求
30. 412 ~ 一个或多个请求头字段在当前请求中错误
31. 413 ~ 请求的资源大于服务器允许的大小
32. 414 ~ 请求的资源URL长于服务器允许的长度
33. 415 ~ 请求资源不支持请求项目格式
34. 416 ~ 请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
35. 417 ~ 服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求
36. 500 ~ 服务器产生内部错误
37. 501 ~ 服务器不支持请求的函数
38. 502 ~ 服务器暂时不可用,有时是为了防止发生系统过载
39. 503 ~ 服务器过载或暂停维修
40. 504 ~ 关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长
41. 505 ~ 服务器不支持或拒绝支请求头中指定的HTTP版本
Java的几种访问权限
public修饰的类可以在其他任意包访问
protect修饰的类可以在同包内访问
default修饰的类可以在本类和同包中访问
private是私有的意思只能在本类中访问
四个修饰符体现了面向对象的封装性,适用他们尽可能把权限降到最低,从而提高安全性;
权限修饰符分类
权限修饰符 |
本类 |
同一个包下 |
不同包下的子类 |
不同包下的无关类 |
private |
Y |
|
|
|
默认 |
Y |
Y |
|
|
protected |
Y |
Y |
Y |
|
public |
Y |
Y |
Y |
Y |
(1):这四种权限修饰符在任意时刻只能出现一种。
(2):权限访问顺序:public > protected > 默认 > private
(3):应用场景
本类中四种权限修饰符都可以
同包不同类private不可以
常见权限修饰符
权限修饰符:private,默认的,protected,public
状态修饰符:static(静态),final(最终)
抽象修饰符:abstract
private: 用它修饰的方法,只能在定义该方法的类中被访问
public: 用它修饰的方法,用它修饰的方法在任何包中的任何程序中都能被访问。
protected: 用它修饰的方法,可以被所在包中的类或者在任何包中的子类访问
static(静态):用它修饰的方法成为静态方法,可以通过类名直接调用
final: 用它修饰的方法不能在子类中修改,所以称使用它定义的方法为最终方法
abstract: 可以用它定义抽象类,抽象方法必须在具体的子类中实现
(1):修饰类:
权限修饰符:默认修饰符,public
状态修饰符:final
抽象修饰符:abstract
*用的最多的就是:public
(2):修饰成员变量:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:不可用
*用的最多的就是:private
(3):修饰构造方法:
权限修饰符:private,默认的,protected,public
状态修饰符:不可用
抽象修饰符:不可用
*用的最多的就是:public
(4):修饰成员方法:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:abstract
*用的最多的就是:public
(5):除此以外的组合规则:
成员变量:public static final //静态成员方法
成员方法:public static
public abstract
public final
arr[y+1]) { int temp = arr[y]; arr[y] = arr[y+1]; arr[y+1] = temp; } } } } " v:shapes="文本框_x0020_2">冒泡排序
value) { max = mid - 1; }else if(arr[mid] < value) { min = mid + 1; } if(min > max) { return -1; } mid = (min+max)/2; } return mid; } " v:shapes="_x0000_s2051">二分查找
选择排序
两个对象值相同(x.equals(y)==true),但hashCode不同,这句话对不对
答:不对,有相同的 hashCode
这是java语言的定义:
1) 对象相等则hashCode一定相等;
2) hashCode相等对象未必相等
接口是否可继承接口
接口可以继承接口.但是要使用extends而不是用implements
如:interface a{}
interface b extends a{}
抽象类是否可实现(implements)接口
抽象类可以实现接口
如:java.util中的AbstractCollection类就是实现的Collection接口
抽象类是否可以继承实体类
抽象类可以继承实体类
下面这段执行无误的代码说明了所有的问题:
interface MyInterface {}
interface AnotherInterface extends MyInterface {}
class EntityClass {}
abstract class AbstractClass extends EntityClass implements MyInterface {}
String s=new String("xyz")创建了几个对象
分为两种情况:
- 如果String常量池中,已经创建"xyz",则不会继续创建,此时只创建了一个对象new String("xyz");
- 如果String常量池中,没有创建"xyz",则会创建两个对象,一个对象的值是"xyz",一个对象new String("xyz")。
while循环和for循环的区别
(1)使用区别:
a) 如果你想在循环结束后,继续使用控制条件的那个变量,用while循环,否则用for循环。不知道用for循环。因为变量及早的从内存中消失,可以提高内存的使用效率。
b) 变量名不能重名,重名是非法的,不同的作用域是可以的、建议:永远不要重名
(2)其实还有一种场景的理解:
如果是一个范围的,用for循环非常明确。
如果是不明确要做多少次,用while循环较为合适。举例:吃葡萄。
Override和Overload的区别
Override:方法重写,在子类中,出现和父类中一模一样的方法声明的现象。
Overload:方法重载,同一个类中,出现的方法名相同,参数列表不同的现象。
Overload是否可以改变返回值类型
返回值类型:方法重载能改变返回值类型,因为它和返回值类型无关。
String,StringBuffer,StringBuilder的区别
- String 类代表字符串。
- StringBuilder替代了StringBuffer
- StringBuilder:线程不安全,效率高,
- StringBuffer:线程安全,效率低。
- 数组类Array
Array和Arrays的区别
Java中最基本的一个存储结构。
提供了动态创建和访问 Java 数组的方法。其中的元素的类型必须相同。
效率高,但容量固定且无法动态改变。
它无法判断其中实际存有多少元素,length只是告诉我们array的容量。
- 静态类Arrays
此静态类专门用来操作array ,提供搜索、排序、复制等静态方法。
equals():比较两个array是否相等。array拥有相同元素个数,且所有对应元素两两相等。
sort():用来对array进行排序。
binarySearch():在排好序的array中寻找元素。
Integer和int的区别
- Integer 是引用类型 int 是基本类型
- 初始化值不一样
- 内存不一样
基本类型在栈帧
引用类型在堆中
- Integer更符合面向对象的思想,功能更强大,增强了代码复用性
Integer类型比较相等
- Integer是int类型的包装类对象,既然是对象它的地址值就不相等
- Integer的取值范围是【-128,127】,即在此范围内的Integer类型可以使用 == 进行对比,超出此范围则需要使用 equals 对比
实际上在我们用Integer a = 数字;来赋值的时候Integer这个类是调用的public static Integer valueOf(int i)这个方法。
我们来看看ValueOf(int i)的代码,可以发现他对传入参数i做了一个if判断。在-128<=i<=127的时候是直接用的int原始数据类型,而超出了这个范围则是new了一个对象。
我们知道"=="符号在比较对象的时候是比较的内存地址,而对于原始数据类型是直接比对的数据值。那么这个问题就解决了。
还有一点需要注意到是Integer e=128; int e1=128; e==e1:true而Integer b=128; Integer b1=128;b==b1:false,e=128已经大于127了,所以e是一个对象(new 出来的)为什e=e1是ture,因为int为值类型,
引用类型Integer与值类型int比较显然比较的是值因为int在堆中是不开辟内存的,他在栈中的值则为他本身的值所以e==e1比较的是他们各自的value, e==e1为true
见图
基本数据类型:4类8种(越小越节省空间)
整数(关键字) |
占用字节数 |
byte (字节) |
1 |
short(短整型) |
2 |
int (整型) |
4 |
long (长整型) |
8 |
浮点数 (小数) |
占用字节数 |
float |
4 |
double |
8 |
字符 |
占用字节数 |
char |
2 |
布尔 |
占用字节数 |
boolean |
1 |
为什么说Java是一门平台无关语言
含义是“一次编写到处运行”。Java 能够做到是因为它的字节码(byte code)可以运行在任何操作系统上,与底层系统无关。
为什么 Java 不是100%面向对象
因为它包含8个原始数据类型,例如boolean、byte、char、int、float、double、long、short。
它们不是对象。
Java类加载器以及之间的关系
类加载器:
- 引导类加载器(bootstrap class loader):只加载 JVM 自身需要的类,包名为 java、javax、sun 等开头。
- 扩展类加载器(extensions class loader):加载 JAVA_HOME/lib/ext 目录下或者由系统变量 -Djava.ext.dir 指定位路径中的类库。
- 应用程序类加载器(application class loader):加载系统类路径 java -classpath 或 -Djava.class.path 下的类库。
- 自定义类加载器(java.lang.classloder):继承 java.lang.ClassLoader 的自定义类加载器。
它们的关系:
启动类加载器,C++实现,没有父类。
扩展类加载器(ExtClassLoader),Java 实现,父类加载器为 null。
应用程序类加载器(AppClassLoader),Java 实现,父类加载器为 ExtClassLoader 。
自定义类加载器,父类加载器为AppClassLoader
Spring中常用注解
@Required
@PostConstruct
注册:@Controller @Service @Component
注入:@Autowired @Resource
请求地址:@RequestMapping
返回具体数据类型而非跳转:@ResponseBody
分布式、高并发、多线程的区别
他们三个总是相伴而生,但侧重点又有不同。
(1)什么是分布式?
分布式更多的一个概念,是为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段。
该领域需要解决的问题极多,在不同的技术层面上,又包括:分布式文件系统、分布式缓存、分布式数据库、分布式计算等,一些名词如Hadoop、zookeeper、MQ等都跟分布式有关。
从理念上讲,分布式的实现有两种形式:
水平扩展:当一台机器扛不住流量时,就通过添加机器的方式,将流量平分到所有服务器上,所有机
器都可以提供相当的服务;
垂直拆分:前端有多种查询需求时,一台机器扛不住,可以将不同的需求分发到不同的机器上,比如
A机器处理余票查询的请求,B机器处理支付的请求。
(2)什么是高并发?
相对于分布式来讲,高并发在解决的问题上会集中一些,其反应的是同时有多少量:比如在线直播服务,同时有上万人观看。
高并发可以通过分布式技术去解决,将并发流量分到不同的物理服务器上。但除此之外,还可以有很多其他优化手段:
比如使用缓存系统,将所有的,静态内容放到CDN等;还可以使用多线程技术将一台服务器的服务能力最大化。
(3)什么是多线程?
多线程是指从软件或者硬件上实现多个线程并发执行的技术,它更多的是解决CPU调度多个进程的问题,从而让这些进程看上去是同时执行(实际是交替运行的)。
这几个概念中,多线程解决的问题是最明确的,手段也是比较单一的,基本上遇到的最大问题就是线程安全。
在JAVA语言中,需要对JVM内存模型、指令重排等深入了解,才能写出一份高质量的多线程代码。
总结:
分布式是从物理资源的角度去将不同的机器组成一个整体对外服务,技术范围非常广且难度非常大,有了这个基础,高并发、高吞吐等系统很容易构建;
高并发是从业务角度去描述系统的能力,实现高并发的手段可以采用分布式,也可以采用诸如缓存、CDN等,当然也包括多线程;
equals()方法、hashCode()方法的区别
HashCode被设计用来提高性能。
如果两个对象相等(equal),那么他们一定有相同的哈希值。
如果两个对象的哈希值相同,但他们未必相等(equal)。
进程与线程的区别
- 一个程序至少有一个进程,一个进程至少有一个线程,线程是依赖于进程存在的,线程是一个进程中代码的不同的执行路线;
- 进程是对运行时程序的封装,是操作系统进行资源调度和分配的最小单位,实现了操作系统的并发;线程是程序执行的最小单位,是CPU调度和分派的基本的单位,实现进程内部的并发。
进程的五种状态
- 创建状态:进程刚被创建,尚未进入就绪队列。创建进程需要两个步骤:即为新进程分配所需要的资源和空间,设置进程为就绪态,并等待调度执行。
- 就绪状态:进程已获得除CPU以外的所需的一切资源,一旦得到CPU资源即可运行;
- 运行状态:进程正在处理器上面运行
- 阻塞状态:进程正在等待某一事件而暂停运行,如等待某资源或者等待 IO 操作完成,即使CPU 空闲,该进程也不能运行;
- 终止状态:进程达到正常结束点或因其他原因被终止,下一步将被撤销。 终止一个进程需要两个步骤:先等待操作系统或相关的进程进行善后处理;然后回收占用的资源并被系统删除。
线程的七种状态
线程划分为以下几种状态:创建(new)、就绪(runnable/start)、运行(running)、阻塞(blocked)、等待(waiting)、时间等待(time waiting) 和 消亡(dead/terminated)。在某一时刻,一个线程只能处于一种状态。
自我介绍
大家好,我叫孙盼虎,今年29了,现住北京朝阳区,截至目前工作6年了,上家公司是几个小伙伴一起开的,在公司主要负责需求评审,技术难点评估,任务安排以及业务功能开发,有时也客串一下前端来对接接口和微调样式,因为人员比较少的原因,公司项目服务端业务百分之八九十都是我自己负责的,项目中遇到的磕磕绊绊也让自己的能力提升了很多,可能对于一些理论知识描述不怎么到位,但我相信开发上没问题,也希望接下来的面试中各位面试官多多担待。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了