基础篇
基本功
面向对象的特征
面向对象三大特征:
(1)封装(Encapsulation)
所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
(2)继承(Inheritance)
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
(3)多态(Polymorphism)
所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
最常见的多态就是将子类传入父类参数中,运行时调用父类方法时通过传入的子类决定具体的内部结构或行为。
面向对象五大原则:
单一职责原则:一个类只做它该做的事情。
单一职责原则想表达的就是”高内聚”,写代码最终极的原则只有六个字”高内聚、低耦合”
开闭原则:软件实体应当对扩展开放,对修改关闭。
在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。
依赖倒转原则:面向接口编程。
该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代,请参考下面的里氏替换原则。
里氏替换原则:任何时候都可以用子类型替换掉父类型。
需要注意的是:子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。
接口隔离原则:接口要小而专,绝不能大而全。
合成聚合复用原则:优先使用聚合或合成关系复用代码。
迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。
final,finally, finalize 的区别
final用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承.
finally是异常处理语句结构的一部分,表示总是执行.
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖 此方法提供垃圾收集时的其他资源回收,例如关闭文件等.JVM不保证此方法总被调用.
int和Integer有什么区别
Integer类在对象中包装了一个基本类型int的值。Integer类型的对象包含一个int类型的字段。
此外,该类提供了多个方法,能在int类型和String类型之间互相转换,还提供了处理int类型时非常有用的其他一些常量和方法。
重载和重写的区别
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
抽象类和接口有什么区别
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4.抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为publicabstract类型。
5.抽象类中可以包含静态方法,接口中不能包含静态方法
6.抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是publicstatic final类型,并且默认即为publicstatic final类型。
说说反射的用途及实现
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
主要作用有三:
运行时取得类的方法和字段的相关信息。
创建某个类的新实例(.newInstance())
取得字段引用直接获取和设置对象字段,无论访问修饰符是什么。
用处如下:
观察或操作应用程序的运行时行为。
调试或测试程序,因为可以直接访问方法、构造函数和成员字段。
通过名字调用不知道的方法并使用该信息来创建对象和调用方法。
说说自定义注解的场景及实现
HTTP请求的GET与POST方式的区别
在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET和POST。
GET-从指定的资源请求数据。
POST-向指定的资源提交要被处理的数据
session与cookie区别
1,session在服务器端,cookie在客户端(浏览器)
2,session默认被存在在服务器的一个文件里(不是内存)
3,session的运行依赖sessionid,而sessionid 是存在cookie中的,也就是说,如果浏览器禁用了cookie,同时session也会失效(但是可以通过其它方式实现,比如在url中传递session_id)
4,session可以放在文件、数据库、或内存中都可以。
5,用户验证这种场合一般会用session
因此,维持一个会话的核心就是客户端的唯一标识,即sessionid
cookie和session的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
session分布式处理
JDBC流程
1)向DriverManager类注册驱动数据库驱动程序,
Class.forName( "com.somejdbcvendor.TheirJdbcDriver" );
2)调用DriverManager.getConnection方法, 通过JDBC URL,用户名,密码取得数据库连接的Connection对象。
Connection conn = DriverManager.getConnection( "jdbc:somejdbcvendor:other data needed by some jdbc vendor", //URL "myLogin", // 用户名 "myPassword" ); // 密码
3)获取Connection后,便可以通过createStatement创建Statement用以执行SQL语句。下面是一个插入(INSERT)的例子:
Statement stmt = conn.createStatement(); stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
4)有时候会得到查询结果,比如select,得到查询结果,查询(SELECT)的结果存放于结果集(ResultSet)中。
ResultSet rs = stmt.executeQuery( "SELECT * FROM MyTable" );
5)关闭数据库语句,关闭数据库连接。
rs.close(); stmt.close();
MVC设计思想
模型(Model) 用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“Model”有对数据直接访问的权力,例如对数据库的访问。“Model”不依赖“View”和“Controller”,也就是说,Model不关心它会被如何显示或是如何被操作。但是Model中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此Model的View必须事先在此Model上注册,从而,View可以了解在数据Model上发生的改变。(比较:观察者模式(软件设计模式))
视图(View)能够实现数据有目的的显示(理论上,这不是必需的)。在View中一般没有程序上的逻辑。为了实现View上的刷新功能,View需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
控制器(Controller)起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据Model上的改变。
equals与==的区别
总结:默认情况下也就是从超类Object继承而来的equals方法与‘==’是完全等价的,比较的都是对象的内存地址,但我们可以重写equals方法,使其按照我们的需求的方式进行比较,如String类重写了equals方法,使其比较的是字符的序列,而不再是内存地址。
RESTfulAPI
URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。
看Url就知道要什么
看httpmethod就知道干什么
看httpstatus code就知道结果如何
集合
List和Set区别
List和Map区别
Arraylist与LinkedList区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。ArrayList与Vector区别
1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
2.Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
3.LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
HashMap和Hashtable的区别
HashSet和HashMap区别
HashMap和ConcurrentHashMap的区别
HashMap的工作原理及代码实现
ConcurrentHashMap的工作原理及代码实现
线程
创建线程的方式及实现
sleep()、join()、yield()有什么区别
①sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
②线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。Sleep()与wait()的区别
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(waitpool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lockpool),如果线程重新获得对象的锁就可以进入就绪状态。
-wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
-sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
-notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
-notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
说说CountDownLatch原理
说说CyclicBarrier原理
说说Semaphore原理
Java5还提供了信号量机制(semaphore),信号量可以用来限制对某个共享资源进行访问的线程的数量。在对资源进行访问之前,线程必须得到信号量的许可(调用Semaphore对象的acquire()方法);在完成对资源的访问后,线程必须向信号量归还许可(调用Semaphore对象的release()方法)。
说说Exchanger原理
Exchanger是一个线程间协作的工具类,用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange方法,当两个线程都达到同步点,这两个就可以交换数据,将本线程生产出来的数据传递给对方。
说说CountDownLatch与CyclicBarrier区别
CountDownLatch:允许一个或多个线程等待其他线程完成操作.CyclicBarrier:阻塞一组线程直到某个事件发生。
闭锁用于等待事件、栅栏是等待线程.
闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数。
CountDownLatch是一次性的,CyclicBarrier可以重用。
CountDownLatch一个线程(或者多个),等待另外N个线程完成某个事情之后才能执行。CyclicBarrier是N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。CountDownLatch是计数器,线程完成一个就记一个,就像报数一样,只不过是递减的.而CyclicBarrier更像一个水闸,线程执行就像水流,在水闸处都会堵住,等到水满(线程到齐)了,才开始泄流.
ThreadLocal原理分析
ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本
讲讲线程池的实现原理
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。
线程池的几种方式
Java5+中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,因此在工具类Executors面提供了一些静态工厂方法,生成一些常用的线程池,如下所示:
-newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
-newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
-newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
-newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
-newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。线程的生命周期
锁机制
说说线程安全问题
volatile实现原理
synchronize实现原理
synchronized与lock的区别
Lock是Java5以后引入的新的API,和关键字synchronized相比主要相同点:Lock能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally块中释放(这是释放外部资源的最好的地方)。
Synchronized块不能保证等待进入块的线程的访问顺序;
Synchronized块无法接收参数,不能在有超时时间限制的情况下尝试访问;
Synchronized块必须包含在单个方法中,而锁的lock和unlock操作可以在单独的方法中
相同:显示锁与内置锁在加锁和内存上提供的语义相同(互斥访问临界区)不同:1.使用方式,内置无需指定释放锁,简化锁操作。显示锁拥有锁获取和释放的可操作性。2.功能上:显示锁提供了其他很多功能如定时锁等待、可中断锁等待、公平性、尝试非阻塞获取锁、以及实现非结构化的加锁。(一个线程获取不到锁而被阻塞在synchronized之外时,对该线程进行中断操作,此时该线程的中断表示为会被修改,但线程依旧会被阻塞在synchronized上,等待获取锁。)3.对死锁的处理:内置只能重启,显示可以通过设置超时获取锁来避免4.性能上:java1.5显示远超内置,java1.6显示锁稍微比内置好
CAS乐观锁
CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。(在CAS的一些特殊情况下将仅返回CAS是否成功,而不提取当前值。)CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”这其实和乐观锁的冲突检查+数据更新的原理是一样的。
这里再强调一下,乐观锁是一种思想。CAS是这种思想的一种实现方式。
ABA问题
部分乐观锁的实现是通过版本号(
version
)的方式来解决ABA问题,乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1
操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现ABA问题,因为版本号只会增加不会减少。乐观锁的业务场景及实现方式
悲观锁会锁定数据,其他操作不会影响到被锁的数据,但是普通的查询没有影响,需要用到forupdate语句
悲观锁的确保了数据的安全性,在数据被操作的时候锁定数据不被访问,但是这样会带来很大的性能问题。因此悲观锁在实际开发中使用是相对比较少的。
实现乐观锁的方法是在数据表中增加一个version字段,每当数据更新的时候这个字段执行加1操作。这样当数据更改的时候,另外一个事务访问此条数据进行更改的话就会操作失败,从而避免了并发操作错误。
核心篇
数据存储
1 脏读:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题。
但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。
2 不可重复读:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题
3 幻读问题:采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻影读问题,在这里有个描述范围锁的文章
MySQL索引使用的注意事项
说说反模式设计
说说分库与分表设计
分库与分表带来的分布式困境与应对之策
说说SQL优化之道
MySQL遇到的死锁问题
存储引擎的InnoDB与MyISAM
数据库索引的原理
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
为什么要用B-tree
b+树相比于b树的查询优势:
b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”;
b+树查询必须查找到叶子节点,b树只要匹配到即可不用管元素位置,因此b+树查找更稳定(并不慢);
对于范围查找来说,b+树只需遍历叶子节点链表即可,b树却需要重复地中序遍历
聚集索引与非聚集索引的区别
聚簇索引的顺序就是数据的物理存储顺序;
非聚簇索引的解释是:索引顺序与数据物理排列顺序无关。
limit20000 加载很慢怎么解决
选择合适的分布式主键方案
选择合适的数据存储方案
ObjectId规则
聊聊MongoDB使用场景
倒排索引
聊聊ElasticSearch使用场景
缓存使用
Redis有哪些类型
Redis内部结构
聊聊Redis使用场景
Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程。另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不需要转到Redis。
转向Redis当然也是可取的,许多开发者从一开始就把Redis作为首选数据库;但设想如果你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些需要大容量数据集的应用,Redis也并不适合,因为它的数据集不会超过系统可用的内存。所以如果你有大数据应用,而且主要是读取访问模式,那么Redis并不是正确的选择。
然而我喜欢Redis的一点就是你可以把它融入到你的系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决传统环境中碰到的一些常见问题。在这些例子中,Redis都不是作为首选数据库。
1、显示最新的项目列表
2、删除与过滤
3、排行榜相关
4、按照用户投票和时间排序
5、处理过期项目
6、计数
7、特定时间内的特定项目
8、实时分析正在发生的情况,用于数据统计与防止垃圾邮件等
9、Pub/Sub
10、队列
11、缓存
Redis持久化机制
Redis如何实现持久化
Redis集群方案与实现
Redis为什么是单线程的
缓存奔溃
缓存降级
使用缓存的合理性问题
消息队列
消息队列的使用场景
1.异步处理
2.应用解耦
3.流量削锋
4.日志处理
5.消息通信
消息的重发补偿解决思路
消息的幂等性解决思路
消息的堆积解决思路
自己如何实现消息队列
如何保证消息的有序性
框架篇
Spring
BeanFactory和ApplicationContext有什么区别
Bean工厂(BeanFactory)是Spring框架最核心的接口,提供了高级Ioc的配置机制.应用上下文(ApplicationContext)建立在BeanFacotry基础之上,提供了更多面向应用的功能,如果国际化,属性编辑器,事件等等.beanFactory是spring框架的基础设施,是面向spring本身,ApplicationContext是面向使用Spring框架的开发者,几乎所有场合都会用到ApplicationContext
SpringBean 的生命周期
Bean在Spring中的生命周期如下: 实例化。Spring通过new关键字将一个Bean进行实例化,JavaBean都有默认的构造函数,因此不需要提供构造参数。 填入属性。Spring根据xml文件中的配置通过调用Bean中的setXXX方法填入对应的属性。事件通知。Spring依次检查Bean是否实现了BeanNameAware、BeanFactoryAware、ApplicationContextAware、BeanPostProcessor、InitializingBean接口,如果有的话,依次调用这些接口。 使用。应用程序可以正常使用这个Bean了。 销毁。如果Bean实现了DisposableBean接口,就调用其destroy方法。
SpringIOC 如何实现
所谓的”控制反转”就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。
传统模式中对象的调用者需要创建被调用对象,两个对象过于耦合,不利于变化和拓展.在spring中,直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理,从而实现对象之间的松耦合。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。 依赖注入:对象无需自行创建或管理它们的依赖关系,IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。依赖注入能让相互协作的软件组件保持松散耦合。
说说SpringAOP
SpringAOP 实现原理
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。SpringAOP 的实现原理其实很简单:AOP框架负责动态地生成AOP代理类,这个代理类的方法则由Advice和回调目标对象的方法所组成,并将该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异,AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。SpringAOP使用动态代理技术在运行期织入增强代码。使用两种代理机制:基于JDK的动态代理(JDK本身只提供接口的代理);基于CGlib的动态代理。
动态代理(cglib与JDK)
1)JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler只是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑与业务逻辑织在一起。而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理.只能实现接口的类生成代理,而不能针对类
2)CGLib采用底层的字节码技术,为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类的调用方法,并顺势织入横切逻辑.它运行期间生成的代理对象是目标类的扩展子类.所以无法通知final的方法,因为它们不能被覆写.是针对类实现代理,主要是为指定的类生成一个子类,覆盖其中方法.
在spring中默认情况下使用JDK动态代理实现AOP,如果proxy-target-class设置为true或者使用了优化策略那么会使用CGLIB来创建动态代理.Spring AOP在这两种方式的实现上基本一样.以JDK代理为例,会使用JdkDynamicAopProxy来创建代理,在invoke()方法首先需要织入到当前类的增强器封装到拦截器链中,然后递归的调用这些拦截器完成功能的织入.最终返回代理对象.
Spring事务实现方式
Spring事务底层原理
如何自定义注解实现功能
SpringMVC 运行流程
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求
可以根据
第三步:处理器映射器
第四步:前端控制器调用处理器适配器去执行
第五步:处理器适配器去执行
第六步:
第七步:处理器适配器向前端控制器返回
是
第八步:前端控制器请求视图解析器去进行视图解析
根据逻辑视图名解析成真正的视图
第九步:视图解析器向前端控制器返回
第十步:前端控制器进行视图渲染
视图渲染将模型数据
第十一步:前端控制器向用户响应结果
组件:
1、前端控制器DispatcherServlet(不需要程序员开发)
作用接收请求,响应结果,相当于转发器,中央处理器。
有了DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的url查找Handler
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器Viewresolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
SpringMVC 启动流程
Spring的单例实现原理
Spring框架中用到了哪些设计模式
Spring其他产品(SrpingBoot、SpringCloud、SpringSecuirity、SpringData、SpringAMQP 等)
Netty
为什么选择Netty
说说业务中,Netty的使用场景
原生的NIO在JDK1.7 版本存在epollbug
什么是TCP粘包/拆包
TCP粘包/拆包的解决办法
Netty线程模型
说说Netty的零拷贝
Netty内部执行流程
Netty重连实现
微服务篇
微服务
前后端分离是如何做的
微服务哪些框架
你怎么理解RPC框架
说说RPC的实现原理
说说Dubbo的实现原理
你怎么理解RESTful
说说如何设计一个良好的API
如何理解RESTfulAPI 的幂等性
如何保证接口的幂等性
说说CAP定理、BASE理论
怎么考虑数据一致性问题
说说最终一致性的实现方案
你怎么看待微服务
微服务与SOA的区别
如何拆分服务
微服务如何进行数据库管理
如何应对微服务的链式调用异常
对于快速追踪与定位问题
微服务的安全
分布式
谈谈业务中使用分布式的场景
Session分布式方案
分布式锁的场景
分布是锁的实现方案
分布式事务
集群与负载均衡的算法与实现
说说分库与分表设计
分库与分表带来的分布式困境与应对之策
安全问题
安全要素与STRIDE威胁
防范常见的Web攻击
服务端通信安全攻防
HTTPS原理剖析
HTTPS降级攻击
授权与认证
基于角色的访问控制
基于数据的访问控制
性能优化
性能指标有哪些
如何发现性能瓶颈
性能调优的常见手段
说说你在项目中如何进行性能调优
工程篇
需求分析
你如何对需求原型进行理解和拆分
说说你对功能性需求的理解
说说你对非功能性需求的理解
你针对产品提出哪些交互和改进意见
你如何理解用户痛点
设计能力
说说你在项目中使用过的UML图
你如何考虑组件化
你如何考虑服务化
你如何进行领域建模
你如何划分领域边界
说说你项目中的领域建模
说说概要设计
设计模式
你项目中有使用哪些设计模式
面试被问到关于设计模式的知识时,可以拣最常用的作答,例如:
-工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
-代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。
-适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。
-模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。
除此之外,还可以讲讲上面提到的门面模式、桥梁模式、单例模式、装潢模式(Collections工具类和I/O系统中都使用装潢模式)等,反正基本原则就是拣自己最熟悉的、用得最多的作答,以免言多必失。说说常用开源框架中设计模式使用分析
说说你对设计原则的理解
23种设计模式的设计理念
设计模式之间的异同,例如策略模式与状态模式的区别
设计模式之间的结合,例如策略模式+简单工厂模式的实践
设计模式的性能,例如单例模式哪种性能更好。
业务工程
你系统中的前后端分离是如何做的
说说你的开发流程
你和团队是如何沟通的
你如何进行代码评审
说说你对技术与业务的理解
说说你在项目中经常遇到的Exception
说说你在项目中遇到感觉最难Bug,怎么解决的
说说你在项目中遇到印象最深困难,怎么解决的
你觉得你们项目还有哪些不足的地方
你是否遇到过CPU100% ,如何排查与解决
你是否遇到过内存 OOM,如何排查与解决
说说你对敏捷开发的实践
说说你对开发运维的实践
介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色
软实力
说说你的亮点
说说你最近在看什么书
说说你觉得最有意义的技术书籍
工作之余做什么事情
说说个人发展方向方面的思考
说说你认为的服务端开发工程师应该具备哪些能力
说说你认为的架构师是什么样的,架构师主要做什么
说说你所理解的技术专家