java面试笔记整理
程序员文章站
2022-04-12 13:15:36
...
面向对象思想
描述对象及其相互之间关系
对象是属性及其操作的封装类,是类的实例。
实例关系和继承关系是对象之间的静态关系;消息传递是对象之间动态联系的唯一形式,也是计算的唯一形式;方法是消息的序列。
基本数据类型与引用数据类型
1、基本数据类型
基本数据类型只有8种,可按照如下分类
①整数类型:long、int、short、byte
②浮点类型:float、double
③字符类型:char
④布尔类型:boolean
2、引用数据类型
引用数据类型非常多,大致包括:
类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型
例如,String类型就是引用类型。
简单来说,所有的非基本数据类型都是引用数据类型。
基本数据类型和引用数据类型的区别:
1、存储位置
基本数据类型:存在栈内存中(非全局基本数据类型变量)
引用数据类型:放在堆内存中,栈内存中放堆内存的地址值。
2、传递方式
调用方法时作为参数,是按数值传递的
调用方法时作为参数,是按引用传递的
string中常用方法
indexOf():从指定字符提取索引位置
trim():去除字符串两端空格
hashCode():返回此字符串的哈希码
subString():截取字符串
valueOf():转换为字符串
concat():将指定字符串连接到此字符串的结尾
compareTo():用来比较两个字符串的字典顺序
contains(): 检查一个字符串中是否包含想要查找的值
重载和重写
都是java中多态的表现:重写(Override)是在父类子类间的多态、重载(Overload)是在一个类中多态对的体现。
StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。
final关键字
1.修饰变量
final变量经常和static关键字一起使用,作为常量。
final修饰基本数据类型的变量时,必须赋予初始值且不能被改变,修饰引用变量时,该引用变量不能再指向其他对象
2.修饰方法
代表这个方法不可以被子类的方法重写(final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。)
3.修饰类
final类通常功能是完整的,它们不能被继承。
4.修饰的对象
被final修饰的对象内容是可变的,不可被继承
5.final关键字与static对比
static关键字修饰变量时,会使该变量在类加载时就会被初始化,不会因为对象的创建再次被加载,当变量被static 修饰时就代表该变量只会被初始化一次
static关键字
方便在没有创建对象的情况下来进行调用(方法/变量)。
1)static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,
2)static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
3)static代码块
类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
this代表当前对象,
所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。
static是不允许用来修饰局部变量
abstract关键字
抽象方法:
1、从上面的例子中我们可以看到抽象方法跟普通方法是有区别的,它没有自己的主体(没有{}包起来的
业务逻辑),跟接口中的方法有点类似。所以我们没法直接调用抽象方法
2、抽象方法不能用private修饰,因为抽象方法必须被子类实现(覆写),而private权限对于子类来
说是不能访问的,所以就会产生矛盾
3、抽象方法也不能用static修饰,试想一下,如果用static修饰了,那么我们可以直接通过类名调
用,而抽象方法压根就没有主体,没有任何业务逻辑,这样就毫无意义了。
抽象类:
1、用abstract关键字来表达的类,其表达形式为:(public)abstract class 类名{}
2、抽象类不能被实例化,也就是说我们没法直接new 一个抽象类。抽象类本身就代表了一个类型,无法
确定为一个具体的对象,所以不能实例化就合乎情理了,只能有它的继承类实例化。
3、抽象类虽然不能被实例化,但有自己的构造方法(这个后面再讨论)
4、抽象类与接口(interface)有很大的不同之处,接口中不能有实例方法去实现业务逻辑,而抽象类
中可以有实例方法,并实现业务逻辑,比如我们可以在抽象类中创建和销毁一个线程池。
5、抽象类不能使用final关键字修饰,因为final修饰的类是无法被继承,而对于抽象类来说就是
需要通过继承去实现抽象方法,这又会产生矛盾。(后面将写一篇关于finally的文章详细讨论)
接口
接口严格的来讲属于一个特殊的类,而这个类里面只有抽象方法和全局常量,就连构造方法也没有。
接口(Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合。接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口在实际中更多的作用是制定标准的
因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。
IO流
一.流的概念:
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。它的特性是进行数据传输;
二、流的分类
流按照流向数据流向可以分为输入流和输出流。
流按照处理数据类型的单位不同可以分为字节流和字符流。
三、字节流和字符流
字节流:InputStream和OutputStream是java中可以按照最小字节单位读取的流,即每次读写一个字节,字节流是直接连接到输入源的流。
字符流:是以字符为单位进行数据处理的IO流。本质其实就是基于字节流读取时,去查找指定的码表。
字节流与字符流之间的区别:
1.读写单位不同:字节流式以字节(8位2进制)为单位,字符流是以字符为单位,根据码表映射字符,一次可能读多个字节。
2.处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
3.字节流:一次读入或读出是8位二进制。
4.字符流:一次读入或读出是16位二进制。
结论:只要是纯文本数据优先使用字符流,除此之外都使用字节流。
常用的处理流
1.缓冲流:BufferedInputStrean 、BufferedOutputStream、 BufferedReader、 BufferedWriter 增加缓冲功能,避免频繁读写硬盘。
2.转换流:InputStreamReader 、OutputStreamReader实现字节流和字符流之间的转换。
3.数据流: DataInputStream 、DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来。
线程
一、进程与线程
进程:是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,即进程空间或(虚空间)。进程不依赖于线程而独立存在,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程:是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,线程没有自己的虚拟地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。
在Java中,每次程序运行至少启动2个线程:一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM实际上就是在操作系统中启动了一个进程。
JDK8新特性
1.Lambda 表达式
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。
2.方法引用
方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 :: 。
重点:集合底层原理、jvm
线程不安全:ArrayList、hashmap
int与Integer
int不能调用方法,Integer可以
int默认为0;Integr默认:null
mybatis优缺点:
1.sql语句与代码分离,存放于xml配置文件中:
优点:便于维护管理;
缺点: 不方便调试====JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
2.用逻辑标签控制动态SQL的拼接:
优点:用标签代替编写逻辑代码;
缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。====不要使用变通的手段来应对这种复杂的语句。
3.查询的结果集与java对象自动映射:
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点:对开发人员所写的SQL依赖很强。
4.编写原生SQL:
优点:接近JDBC,比较灵活。
缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。
5.MyBatis 中# 和$ 的区别?
这两个符号一般是在使用Mybatis编写底层SQL语句时使用,#就是一个占位符,具体的使用是#{id},而$是一个原样输出的标识,是${value},
我在项目里一直是使用#,因为这样可以防止Sql注入,安全性高。
6.Mybatis 缓存?
mybatis 一级缓存是SqlSession 级别的缓存,默认支持一级缓存,不需要在配置文件去配置。
mybaits 的二级缓存是mapper 范围级别,除了在SqlMapConfig.xml 设置二级缓存的总开关
<settingname='cacheEnabled'value='true'/>,还要在具体的mapper.xml 中开启二级缓存:
<mappernamespace='cn.hpu.mybatis.mapper.UserMapper'>
框架的由来:
框架指的是软件的半成品,已经完成了部分功能。
编程有一个准则,Don't Repeat Yourself(不要重复你的代码)
所以我们会将重复的代码抽取出来,封装到方法中;
如果封装的方法过多,将将这些方法封装成工具类;
如果工具类形成了规模,就整合成类库====框架。
类库更加系统,功能更加齐全。既然别人已经造好了*,我们为什么还有闭门造车呢,直接把造好的*拿来用就行了。这就有了框架的诞生。
库是工具,提供大量api,需要调用里面的api使用
框架:提供一整套完整解决方案,使用者需要按照框架的规定进行开发。
框架与架构
设计模式:是在某种特定上下文中,针对一个软件生命周期中出现的问题而给出的多次适用的解决方案。
框架:框架是一组软件组件,它们互相协作提供了针对某个给定的问题领域中的应用程序所用到的一种可复用的体系结构。
可重复使用的代码类库。
架构:又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。
简单的说架构就是一个蓝图,是一种设计方案,将客户的不同需求抽象成为抽象组件,并且能够描述这些抽象组件之间的通信和调用。
架构(动词)>框架>设计模式。
软件通过架构,可以设计出很多不同的框架。在一个框架中,也可以使用很多的设计模式。设计模式不是哪儿哪儿都可以用的,只有当出现了某一特定的问题时,才利用设计模式去解决。设计模式不是用的越多越好,在维护的时候,过多的设计模式会极大的增添维护成本。
悲观锁与乐观锁
乐观锁:适用于写比较少的情况下(多读场景)
悲观锁:多写的场景下用悲观锁就比较合适。
数组与链表
数组;就是相同数据类型的元素按一定顺序排列的集合;数组的存储区间是连续的,占用内存比较大,故空间复杂的很大。但数组的二分查找时间复杂度小,都是O(1);数组的特点是:查询简单,增加和删除困难;
数组的优点:
随机访问性强,查找速度快,时间复杂度是0(1)
三、数组的缺点:
3.1 从头部删除、从头部插入的效率低,时间复杂度是o(n),因为需要相应的向前搬移和向后搬移。
3.2 空间利用率不高
3.3 内存空间要求高,必须要有足够的连续的内存空间。
3.4 数组的空间大小是固定的,不能进行动态扩展。
链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:查询相对于数组困难,增加和删除容易。
链表的优点
2.1 任意位置插入元素和删除元素的速度快,时间复杂度是o(1)
2.2 内存利用率高,不会浪费内存
2.3 链表的空间大小不固定,可以动态拓展。
三、链表的缺点
随机访问效率低,时间复杂度是o(1)
在Java中,如何跳出当前的多重嵌套循环?
1.在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。
2.外层的循环条件表达式的结果可以受到里层循环体代码的控制,在外层循环中加一个&&变量(布尔),通过在里层循环修改变量的值,跳出循环
Java Runnable与Callable区别
相同点:
都是接口
都可以编写多线程程序
都采用Thread.start()启动线程
不同点:
Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
注:Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
Java中notify和notifyAll的区别
然后再来说notify和notifyAll的区别
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
forward和redirect
servlet种的两种主要的跳转方式。forward又叫转发,redirect叫做重定向。
两者的区别总结:
1. 从地址栏显示来说:
1)forword是服务器内部的重定向,服务器直接访问目标地址的 url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的。
2)redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址。
2。 从数据共享来说:
1)由于在整个定向的过程中用的是同一个request,因此forward会将request的信息带到被重定向的jsp或者servlet中使用。即可以共享数据
2)redirect不能共享
3. 从运用的地方来说
1)forword 一般用于用户登录的时候,根据角色转发到相应的模块
2) redirect一般用于用户注销登录时返回主页面或者跳转到其他网站
4。 从效率来说:
1)forword效率高,而redirect效率低
5. 从本质来说:
forword转发是服务器上的行为,而redirect重定向是客户端的行为
6. 从请求的次数来说:
forword只有一次请求;而redirect有两次请求,
内存溢出,内存泄漏
1、内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
2、内存溢出 out of memory :指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
内存溢出原因:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小
内存溢出的解决方案:
第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
SSH与SSM
SSH(Struts2+Spring+Hibernate)
SSM(SpringMVC+Spring+MyBatis)。
ORM:对象关系映射
指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表
利用描述对象和数据库表之间映射的元数据,自动把Java应用程序中的对象,持久化到关系型数据库的表中。通过操作Java对象,就可以完成对数据库表的操作。可以把ORM理解为关系型数据和对象的一个纽带,开发人员只需要关注纽带一端映射的对象即可。
控制反转IoC
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
BeanFactory 和 ApplicationContext有什么区别
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
1.依赖关系:BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
继承MessageSource,因此支持国际化。
统一的资源文件访问方式。
提供在监听器中注册bean的事件。
同时加载多个配置文件。
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
2.加载方式:BeanFactroy采用的是延迟加载形式来注入Bean,ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。
3.创建方式:BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
4.注册方式:BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
什么是Spring beans?
Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。
给Spring 容器提供配置元数据。
XML配置文件。
基于注解的配置。
基于java的配置。
单点登陆:
简称为 SSO,是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
SSO单点登录完美解决session共享问题
使用cas框架:
【1】开源的企业级单点登录解决方案。
【2】CAS Server 为需要独立部署的 Web 应用。
【3】CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
SSO单点登录访问流程:
1. 访问服务:用户向SSO客户端发送请求访问应用系统提供的服务资源。
2. 定向认证:SSO客户端会重定向用户请求到SSO服务器。
3. 用户认证:用户身份认证。
4. 发放票据:SSO服务器会产生一个随机的Service Ticket:令牌。
5. 验证票据:SSO服务器验证票据Service Ticket的合法性,验证通过后,允许客户端访问服务。
6. 传输用户信息:SSO服务器验证票据通过后,传输用户认证结果信息给客户端。
1.当用户第一次登陆时,先通过SSO单点登录系统进行登录操作.
2.根据用户信息查询用户数据验证登录是否有效
3.如果用户名和密码都正确,则生成ticket.并将User对象转化为JSON数据
4.将ticket和UserJSON数据写入redis缓存中
5.当用户登陆成功后,在cookie保存ticket信息.
6.当用户再次访问前台系统时,首先根据ticket信息,查询redis缓存服务器.获取用户数据.
7.当用户访问购物车时,首先前台会校验,根据ticket查询用户信息,如果用户没有登陆则转向单点登录系统.
8.当用户访问订单系统时,首先前台会校验,根据ticket查询用户信息,如果没有该用户信息,则转向单点登录系统.
工程搭建:
1、引入依赖:cas-client-core
2.添加web.xml
3.cas系统的配置文件cas-servlet.xml
4.配置数据源:
(1)修改cas服务端中WEB-INF下deployerConfigContext.xml ,添加如下配置
(注意数据库,root账号是否允许远程连接。还要关闭防火墙。)
(2)将以下三个jar包放入webapps\cas\WEB-INF\lib下
消息中间件:ActiveMQ
概念:是基于Java 中的JMS 消息服务规范实现的一个消息中间件。
使用的好处:减轻服务器压力,降低项目之间的耦合度(解耦),是做异步的.
ActiveMQ 可以发送的消息类型:
TextMessage--一个字符串对象
· MapMessage--一套名称-值对
· ObjectMessage--一个序列化的Java 对象
· BytesMessage--一个字节的数据流
· StreamMessage -- Java 原始值的数据流
我项目中用过text map object 这三个类型
ActiveMQ 心跳机制:
还有这个ActiveMQ 还有一个心跳的机制,这种机制可以判断收发双方链路是否通畅,它内
部使用的机制是双向心跳,也就是ActiveMQ 的生产者和消费者都进行相互心跳。心跳这里
会产生两个线程,一个是“ReadCheck”“WriteCheck”,它们都是timer 类型,每隔一段时
间都会被调用一次.
改善系统模块调用关系、减少模块之间的耦合
中常见的角色大致有Producer(生产者)、Consumer(消费者)
模式,JMS消息传递类型:
1 点对点
2 发布/订阅
优势:
4.1 系统解耦
交互系统之间没有直接的调用关系,只是通过消息传输,故系统侵入性不强,耦合度低。
4.2 提高系统响应时间
例如原来的一套逻辑,完成支付可能涉及先修改订单状态、计算会员积分、通知物流配送几个逻辑才能完成;通过MQ架构设计,就可将紧急重要(需要立刻响应)的业务放到该调用方法中,响应要求不高的使用消息队列,放到MQ队列中,供消费者处理。
4.3 为大数据处理架构提供服务
通过消息作为整合,大数据的背景下,消息队列还与实时处理架构整合,为数据处理提供性能支持。
4.4 Java消息服务——JMS
Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
JMS中的P2P和Pub/Sub消息模式:点对点(point to point, queue)与发布订阅(publish/subscribe,topic)最初是由JMS定义的。这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅)。
JMS
JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
侵入性
在java里侵入性,一般指的是:使用一个新的技术不会或者基本不改变原有代码结构,原有代码不作任何修改即可.像spring就是非侵入式的开源框架.
集合
Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└ HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序
Map 接口 键值对的集合 (双列集合)
├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全-
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap
list和set的区别:
数组和集合的区别
Collection集合的方法
map集合的方法
商品搜索系统的搭建
1.solr:Apache Solr是一个流行的开源搜索服务器,它通过使用类似REST的HTTP API,确保你能从几乎任何编程语言来使用solr。
2.core:是solr的特有概念,每个core是一个查询数据、索引等的集合体,你可以把它想象成一个独立数据库
3.中文分析器IK Analyzer:是一个开源的,基于 java 语言开发的轻量级的中文分词工具包
4.域:增加域、复制域(将多个域合并为一个域)、动态域(动态扩充字段)
5.集成spring的框架:spring-data-solr
网页静态化技术:Freemarker
网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁的数据。另外网页静态化还有利于SEO
使用Nginx这样的高性能的web服务器来部署。
FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。
模板文件中四种元素
1、文本,直接输出的部分
2、注释,即<#--...-->格式不会输出
3、插值(Interpolation):即${..}部分,将使用数据模型中的部分替代输出
4、FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出
生成文件
第一步:创建一个 Configuration 对象,直接 new 一个对象。构造方法的参数就是 freemarker的版本号。
第二步:设置模板文件所在的路径。
第三步:设置模板文件使用的字符集。一般就是 utf-8.
第四步:加载一个模板,创建一个模板对象。
第五步:创建一个模板使用的数据集,可以是 pojo 也可以是 map。一般是 Map。
第六步:创建一个 Writer 对象,一般创建一个 FileWriter 对象,指定生成的文件名。
第七步:调用模板对象的 process 方法输出文件。
第八步:关闭流
FTL指令
assign指令:在页面上定义一个变量 ,<#assign linkman="优就业小优">
include指令:用于模板文件的嵌套,<#include "head.ftl">
if指令:<#if success=true>
你已通过实名认证
<#else>
你未通过实名认证
</#if>
list指令:<#list goodsList as goods>
内建函数
1.获取集合大小:共 ${goodsList?size} 条记录
2.转换JSON字符串为对象: <#assign text="{'bank':'工商行','account':'18901920201920212'}" />
<#assign data=text?eval />
3.日期格式化:
map.put("today", new Date());
当前日期:${today?date} <br>
当前时间:${today?time} <br>
当前日期+时间:${today?datetime} <br>
日期格式化: ${today?string("yyyy年MM月")}
4.数字转换为字符串:累计积分:${point?c}
比较运算符:
1 =或者== 判断两个值是否相等.
2 != 判断两个值是否不等.
3 >或者gt 判断左边值是否大于右边值
4 >=或者gte 判断左边值是否大于等于右边值
5 <或者lt 判断左边值是否小于右边值
6 <=或者lte 判断左边值是否小于等于右边值
nginx
Nginx就是性能非常好的反向代理服务器,用来做负载均衡。
Nginx是一款高性能的、轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like协议下发行。由俄罗斯的程序设计师lgor Sysoev所开发,供俄国大型的入口网站及搜索引擎Rambler(俄文:PaM6nep)使用。其特点是占有内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现较好,*使用Nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
优点:稳定性、丰富的模块库、灵活的配置和低系统资源的消耗、响应静态页面的速度非常快
高并发。静态小文件
占用资源少。2万并发、10个线程,内存消耗几百M。
功能种类比较多。web,cache,proxy。每一个功能都不是特别强。
支持epoll模型,使得nginx可以支持高并发。
nginx 配合动态服务和Apache有区别。(FASTCGI 接口)
利用nginx可以对IP限速,可以限制连接数。
配置简单,更灵活。
代理
正向代理:vpn,通过香港的节点去访问外网,外网不知道是我们在访问,只知道我们使用的节点在访问,不知道请求客户端是谁====为客户端代理
反向代理:反向代理隐藏了真实的服务端,我们不需要知道哪个服务器提供的服务====为服务端代理。
Git
Git是一款免费、开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。
dubbo
0. 服务容器负责启动,加载,运行服务提供者。
1. 服务提供者在启动时,向注册中心注册自己提供的服务。
2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推
送变更数据给消费者。
4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,
如果调用失败,再选另一台调用。
5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计
数据到监控中心。
Dubbo 容错策略:失败重试,失败自动恢复, 并行调用,广播调用
如何保证mysql与redis一致性
1.分别处理
实时性不强的业务:将这些数据放入Redis,请求来了直接查询Redis
强实时性的业务:直接穿透Redis至MySQL上,等到MySQL上写入成功,再同步更新到Redis上去
2.高并发情况下
如果写入请求较多,则直接写入Redis中去,然后间隔一段时间,批量将所有的写入请求,刷新到MySQL中去;
如果此时写入请求不多,则可以在每次写入Redis,都立刻将该命令同步至MySQL中去。这两种方法有利有弊,需要根据不同的场景来权衡。
3.基于订阅binlog的同步机制
阿里巴巴的一款开源框架canal,提供了一种发布/ 订阅模式的同步机制,通过该框架我们可以对MySQL的binlog进行订阅,这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。值得注意的是,binlog需要手动打开,并且不会记录关于MySQL查询的命令和操作。
读请求:
不要求强一致性的读请求,走redis,要求强一致性的直接从mysql读取
写请求:
数据首先都写到数据库,之后更新redis(先写redis再写mysql,如果写入失败事务回滚会造成redis中存在脏数据)
MVC
M 代表 模型(Model)
模型是什么呢? 模型就是数据,就是 dao,bean
V 代表 视图(View)
视图是什么呢? 就是网页, JSP,用来展示模型中的数据
C 代表 控制器(controller)
控制器是什么? 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。
SpringMVC
传统的模型层被拆分为了业务层(Service)和数据访问层(DAO,Data Access Object)。 在 Service 下可以通过 Spring 的声明式事务操作数据访问层,而在业务层(service)上还允许我们访问 NoSQL ,这样就能够满足异军突起的 NoSQL 的使用了,它可以大大提高互联网系统的性能。
注解:NoSQL,泛指非关系型的数据库
特点:
结构松散,几乎可以在 Spring MVC 中使用各类视图
松耦合,各个模块分离
与 Spring 无缝集成
springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。
springmvc是一个基于mvc的web框架。
springmvc 表现层:方便前后端数据的传输
Spring MVC 拥有控制器,作用跟Struts类似,接收外部请求,解析参数传给服务层
Spring 中@Autowired 和@Resource 的区别?
@Autowired 默认的是按照类型进行注入, 如果没有类型会按照名称(红色字体)进行注入.
如果想直接按照名称注入需要加入@Qualifier("gatheringDao")
@Autowired
@Qualifier("gatheringDao")
private GatheringDao gatheringDao;
@Resource 默认的会按照名称注入,名称找不着会按照类型来找,如果这里写了名称,就直接
按照名称找了不会按类型找@Resource(name = "aaa")
@Resource
private GatheringDao gatheringDao;
spring
Spring框架为开发Java应用程序提供了全面的基础架构支持。它包含一些很好的功能,如依赖注入和开箱即用的模块
核心思想,IOC(控制反转),DI(依赖注入),AOP(面向切面编程)。
DI:把我们需要的类啊,接口啥的注入到spring 中去。
IOC:通过配置文件用反射的方式,就可以直接帮我们获取到这个类的对象
AOP:实现了JDK 的动态代理 使用:事务管理,日志打印,还有就是在老项目中也有可能用它来做权限管理.
就像maven 整合了所有的jar 包,spring boot 整合了所有的框架,spring cloud 微服务框架。
spring通过依赖注入机制,解决的是将对象之间的依赖关系交由配置文件统一管理,也就是注入关系在IOC容器中管理。
IOC又是什么呢?就是bean包装的对象。spring就是通过bean完成对这些对象的管理以及一些额外的功能目的。spring的设计策略和Java中的OOP相似,但是较之复杂的多。首先创建一系列数据结构,然后根据数据结构设计生存环境,让数据结构在生存环境中不停的运动,在运动的过程中与环境或者其他个体完成信息交换。其他的框架用到的都是这样的设计准则。
常用的注解:
@service 业务逻辑,@Transactionnal 事务的注解,
注入DAO 的话还会用到@Repository
springMVC 里的注解啦, 比如说@Controller 对应表现层的注解在spring 未来的版本中,
@RestController 这个控制器返回的都是json 格式,
还有@RequestMapping 进入的URL,
@responsebody 也是定义该方法返回JSON 格式,
@RequestParam 获取参数,@RequestBody 获取前台的数据是JSON 格式的数据,
@PathVariable 从URL 请求路径中获取数据,大概常用的也就这些.
spring security
spring security 的核心功能主要包括:
认证 (你是谁)
授权 (你能干什么)
攻击防护 (防止伪造身份)
SpringBoot优点
Spring Boot基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的复杂例行配置。
springboot 是springmvc 的升级版,其实就把springmvc 里的配置文件,改为全注解的开发
快速创建独立运行的Spring 项目以及与主流框架集成jpa mybatis
使用嵌入式的Servlet 容器应用无需打成WAR 包
Starters(场景启动器)自动依赖与版本控制
大量的自动配置,简化开发,也可修改默认值
无需配置大量的XML,无代码生成,开箱即用
SpringCloud 的常用组件
SpringCloud 通过Springboot 把其他的通信组件等等进行了封装, 你如果使用SpringCloud 的, 那就必须得使用SpringBoot, 使用SpringBoot 的话不一定非得使用SpringCloud.
Eureka 组件(服务发现)音标(ju`ri:kə): 相当于我们使用的dubbo 的时候zookeeper注册中心.
Feign 组件: 调用服务的时候用的组件
Hystrix(hist`riks)熔断器: 我们在调用服务的时候,有可能涉及到服务的连锁调用,比如
说A 服务调用B 服务,B 服务里还调用了C 服务, 使用A 服务的时候,B 服务和C 服务都得正
常运行才可以使用,B 调用C 没有调通的时候, B 直接给A 返回内容, 不至于像以前报错.
服务网关zull: 前后端进行调用的时候可以,可以走同一个IP 地址,因为项目端口号太多,
配置这个以后就可以直接走一个端口号,他自动会给你分配具体调用的哪一个端口
分布式配置Spring Cloud Config:我们把多个项目的配置文件归置为一个,修改配置文件以
后,不用再重新部署某一个项目啦.
消息总线:Spring Cloud Bus: 修改完配置文件以后不用重启项目.
SpringBoot与SpringCloud的关系与区别
1、SpringBoot只是一个快速开发框架,算不上微服务框架。使用注解简化了xml配置,内置了Servlet容器,以Java应用程序进行执行。
2、SpringCloud是一系列框架的集合,可以包含SpringBoot。
组合了各公司比较好的服务框架,使用springboot风格封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。
3.联系:
SpringCloud:具备微服务开发的核心技术:RPC远程调用技术;
SpringBoot:的web组件默认集成了SpringMVC,可以实现HTTP+JSON的轻量级传输,编写微服务接口 SpringCloud依赖SpringBoot框架实现微服务开发。
消息队列&消息中间件&JMS
消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见的角色大致也就有Producer(生产者)、Consumer(消费者)
JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
JMS 定义了五种不同的消息正文格式:
· TextMessage--一个字符串对象
· MapMessage--一套名称-值对
· ObjectMessage--一个序列化的 Java 对象
· BytesMessage--一个字节的数据流
· StreamMessage -- Java 原始值的数据流
Java对象序列化
JVM停止运行之后能够保存(持久化)指定的对象,
在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象,对象序列化不会关注类中的静态变量。
持久化对象时、RMI(远程方法调用)时使用
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制,该API简单易用,在本文的后续章节中将会陆续讲到。
Nginx
Nginx 是一款轻量级的Web 服务器/反向代理服务器
主要提供:反向代理、负载均衡、动静分离(静态资源服务)等服务
四个主要组成:
Nginx 二进制可执行文件:由各模块源码编译出一个文件
Nginx.conf 配置文件:控制Nginx 行为
acess.log 访问日志: 记录每一条HTTP 请求信息
error.log 错误日志:
特点:
1、高并发,高性能
2. 可扩展性好(模块化设计,第三方插件生态圈丰富)
3. 高可靠性(可以在服务器行持续不间断的运行数年)
4. 热部署(这个功能对于Nginx 来说特别重要,热部署指可以在不停止Nginx 服务的情
况下升级Nginx)
5. BSD 许可证(意味着我们可以将源代码下载下来进行修改然后使用自己的版本)
反向代理:严格的概念是通过代理服务器来接收网路上的请求,然后将请求转发给内部网路的服务器
反向代理和正向代理区别
代理:代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。
正向代理:类似一个跳板机,代理访问外部资源
反向代理:严格的概念是通过代理服务器来接收网路上的请求,然后将请求转发给内部网路的服务器
正向代理即是客户端代理, 代理客户端, 服务端不知道实际发起请求的客户端.
反向代理即是服务端代理, 代理服务端, 客户端不知道实际提供服务的服务端
推荐阅读
-
Java新特性之Nashorn_动力节点Java学院整理
-
Java8新特性之再见Permgen_动力节点Java学院整理
-
Java8新特性之类型注解_动力节点Java学院整理
-
Java8新特性之深入解析日期和时间_动力节点Java学院整理
-
Java8新特性之精简的JRE详解_动力节点Java学院整理
-
Java的几个重要版本_动力节点Java学院整理
-
Java concurrency集合之ArrayBlockingQueue_动力节点Java学院整理
-
Java concurrency集合之 CopyOnWriteArrayList_动力节点Java学院整理
-
Java concurrency集合之ConcurrentHashMap_动力节点Java学院整理
-
Java concurrency集合之ConcurrentSkipListSet_动力节点Java学院整理