Java开发面试知识点-长期更新

    技术2022-07-11  68

    前言:本节内容长期更新,专门为了扫清盲点复习。采取小标题加链接方式,毕竟明珠在前。内容较为杂碎。

    长期更新

    负一、手撕代码1、Java注解(Java Annotation in Action)2、手写一个生产者/消费者模式(三种方式实现)3、手写快排4、深拷贝和浅拷贝定义,怎么实现深拷贝,clone()方法在实现深拷贝应该怎么写9、静态代理、JDK动态代理、cglib代理的手撕代码10、单例模式的饿汉式、懒汉式、双重检验锁+volatile,线程安全12、手撕适配器模式,两种13、手撕简单工厂模式,枚举类14、手撕装饰者模式 负二、未理解部分1、面向对象或设计模式之六大原则2、二十三种设计模式5、常见的序列化协议有哪些6、分布式系统中一致性哈希算法7、线程池的执行流程与参数8、JUC锁基于什么实现? AQS?12、工厂模式、观察者模式、装饰器模式、设计模式分类的掌握 一、Java基础1、String、StringBuilder、StringBuffer区别2、Java多态3、Java-IO流4、怎么打破双亲委派5、ThreadLocal6、NIO详解(三):IO多路复用模型之select、poll、epoll 二、Java并发1、CAS2、ThreadLocal内存泄漏分析与解决方案3、Java并发——Executor框架详解(Executor框架结构与框架成员) 三、JVM与GC1、Java内存泄漏的排查总结2、 四、数据库1、ACID 五、mysql1、聚簇索引与非聚簇索引(也叫二级索引)2、innodb引擎的4大特性3、MySQL使用全文索引(fulltext index)4、mysql 行级锁的使用以及死锁的预防5、mysql视图6、MySQL 游标的使用7、mysql存储过程8、多表联合查询、连接查询、子查询9、MySQL中 in 和 exists 区别10、mysql-覆盖索引11、mysqldump和xtrabackup备份原理实现说明 六、redis1、Redis中set类型的交集、并集、差集2、Redis:一致性Hash算法3、Redis与LRU4、Reactor模式5、Bitmap和布隆过滤器6、Jedis与Redisson选型对比7、Redis之Redis事务 七、spring框架1、控制反转的理解2、依赖注入的理解3、IOC容器和依赖注入Dependency Injection关系3、Spring 框架中都用到了哪些设计模式4、BeanFactory和ApplicationContext的区别以及关系5、ApplicationContext通常的实现6、Spring Bean作用域7、单例bean是线程安全的吗以及如何处理线程并发问题8、解释Spring框架中bean的生命周期9、自动装配10、AOP的理解11、JDK动态代理和CGLIB动态代理12、5种通知,后置通知与返回通知的区别13、AOP的切入点和连接点的区别以及关注点和横切关注的区别14、spring 的事务隔离15、Spring支持的事务管理类型16、Spring的事务传播行为17、@Component, @Controller, @Repository, @Service 有何区别

    参考链接: Java基础知识面试题(2020最新版) 1、Java开发基础面试知识点 2、equals和HashCode深入理解以及Hash算法原理 3、MyISAM与InnoDB 的区别(9个不同点) 4、MySQL中的全文索引(InnoDB存储引擎)

    负一、手撕代码

    1、Java注解(Java Annotation in Action)

    自己动手实现Java注解(Java Annotation in Action)

    2、手写一个生产者/消费者模式(三种方式实现)

    手写一个生产者/消费者模式(三种方式实现) 注:感觉麻烦了点,还需改

    // 公共阻塞队列,生产和消费都从这里拿 public class PublicQueue<T>{ private BlockingDeque<T> blockingDeque = null; private int capacity; public PublicQueue(int capacity) { this.blockingDeque = new LinkedBlockingDeque<>(capacity); this.capacity = capacity; } public void add(T msg){ if(blockingDeque.size() < capacity){ try{ blockingDeque.push(msg); }catch (Exception e){ e.printStackTrace(); } System.out.println("生产一个商品:" + msg); }else{ System.out.println("队列已满..."); } } public T remove(){ T take = null; if(!blockingDeque.isEmpty()){ try { take = blockingDeque.take(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费一个商品:" + take); }else{ System.out.println("队列已空"); } return take; } } // 生产任务 class ProducerRunnable implements Runnable { private PublicQueue publicQueue; private String name; ProducerRunnable(){} ProducerRunnable(PublicQueue publicQueue, String name){ this.publicQueue = publicQueue; this.name = name; } @Override public void run() { for(int i = 0; i < 20; i++){ publicQueue.add(name + " "+i); // 生产 } } } // 消费任务 class ComsumerRunnable implements Runnable { private PublicQueue publicQueue; private String name; ComsumerRunnable(){} ComsumerRunnable(PublicQueue publicQueue){ this.publicQueue = publicQueue; } @Override public void run() { for(int i = 0; i <20 ; i++){ name = (String) publicQueue.remove(); } } } public class Main { public static void main(String[] args) { PublicQueue publicQueue = new PublicQueue(20); new Thread(new ProducerRunnable(publicQueue, "apple")).start(); new Thread(new ComsumerRunnable(publicQueue)).start(); } }

    3、手写快排

    4、深拷贝和浅拷贝定义,怎么实现深拷贝,clone()方法在实现深拷贝应该怎么写

    注:深拷贝后比较equals需要注意 java实现克隆的三种(很最全面) JAVA clone方法-深复制(深克隆)&浅复制(浅克隆)

    9、静态代理、JDK动态代理、cglib代理的手撕代码

    // 静态和动态代理都需要定义接口,然后实现功能 public interface Target { public String execute(); } public class TargetImpl implements Target { @Override public String execute() { System.out.println("TargetImpl execute"); return "execute"; } } // cglib代理需要类 public class TargetDomain { public String execute(){ String msg = "--------test------------"; System.out.println(msg); return msg; } } // 静态代理 public class StaticProxy implements Target{ private Target target; // 被代理对象 public StaticProxy(Target target){ this.target = target; } @Override public String execute() { System.out.println("static proxy begin..."); String result = target.execute(); System.out.println("static proxy end"); return result; } public static void main(String[] args){ Target target = new TargetImpl(); StaticProxy staticProxy = new StaticProxy(target); String execute = staticProxy.execute(); //System.out.println(execute); /* static proxy begin... TargetImpl execute static proxy end*/ } } // 动态代理JDK,Proxy.newProxyInstance(类加载器,接口,处理器) import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyHandler implements InvocationHandler { private Target target; // 被代理对象 public DynamicProxyHandler(Target target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic proxy begin..."); Object result = method.invoke(target, args); // 注意这里反射执行的对象一定是被代理对象 System.out.println("dynamic proxy end"); return result; } public static void main(String[] args) { Target target = new TargetImpl(); DynamicProxyHandler handler = new DynamicProxyHandler(target); // 被代理类的类加载器,被代理类的接口,InvocationHandler调用处理逻辑 Target proxy = (Target) Proxy.newProxyInstance(TargetImpl.class.getClassLoader(), TargetImpl.class.getInterfaces(), handler); String result = proxy.execute(); //System.out.println(result); /* dynamic proxy begin... TargetImpl execute dynamic proxy end*/ } } // cglib代理,可以代理一个没有实现接口的非final类,但也可以代理实现接口的非final类,一定要非final是因为通过继承 // Enhancer去代理类,去做方法增强 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; // 方法拦截器的所有逻辑,默认拦截被代理对象的所有非final方法 public class CglibMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("cglib proxy begin..."); Object result = methodProxy.invokeSuper(obj, args); System.out.println("cglib proxy end"); return result; } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); // 设置需要代理的类 enhancer.setSuperclass(TargetDomain.class); // 设置一个callback对原始类方法做增强 enhancer.setCallback(new CglibMethodInterceptor()); // 另外可以设置方法过滤器,分别对某个或多个方法执行执行callback逻辑 //enhancer.setCallbackFilter(); // 创建代理对象 TargetDomain proxy = (TargetDomain) enhancer.create(); String result = proxy.execute(); //System.out.println(result); /* cglib proxy begin... --------test------------ cglib proxy end */ } }

    10、单例模式的饿汉式、懒汉式、双重检验锁+volatile,线程安全

    // 单例饿汉式,线程安全,饿汉式取实例不需要同步锁,因为加载类就创建了实例 public class SingletonHungry { private static SingletonHungry instance = new SingletonHungry(); private SingletonHungry(){ } public static SingletonHungry getInstance(){ return instance; } } // 单例懒汉式,线程安全,取实例的方法就加了同步 public class SingletonLazy { private static SingletonLazy instance; private SingletonLazy(){ } // 同步方法 public static synchronized SingletonLazy getInstance(){ if(instance == null){ instance = new SingletonLazy(); } return instance; } } // 单例懒汉式,线程安全,双重检验锁+volatile关键字, // 为什么要加volatile关键字(禁止指令重排),是因为new Singleton()不是一个原子操作 public class Singleton { private static volatile Singleton instance = null; private Singleton(){}; // 先前同步方法效率低,原因直接加上同步锁(重度锁),这里先判断不存在后再加锁 public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } }

    12、手撕适配器模式,两种

    Java设计模式----适配器模式

    // 被适配器类,已存在,具有特殊功能,但不符合我们的标准接口的类 public class Adaptee { public void specificRequest(){ System.out.println("被适配器类的特殊功能执行..."); } } // 标准接口或目标接口,不能将就,无法更改 interface Target{ void request(); } // 具体目标类,只实现了普通功能 class ConcreteTarget implements Target{ @Override public void request() { System.out.println("标准功能执行..."); } }

    1、类适配器,单继承+实现,+父类调用

    // 适配器类,继承了被适配类,并实现了标准接口 class Adapter extends Adaptee implements Target{ @Override public void request() { super.specificRequest(); // 从标准接口的实现方法中调用特殊功能接口 } } // 客户,测试类 class Client{ public static void main(String[] args) { // 普通功能类,执行普通功能 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 适配器类,执行特殊功能 Target adapter = new Adapter(); // 继承被适配类,实现标准接口,方法中父类调用 //Target adapter = new Adapter(new Adaptee()); // 直接实现标准接口,方法中通过被适配对象调用 adapter.request(); } }

    2、对象适配器,实现+对象调用

    // 适配器类直接实现标准接口 class Adapter implements Target{ private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void request() { adaptee.specificRequest(); } } // 客户,测试类 class Client{ public static void main(String[] args) { // 普通功能类,执行普通功能 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 适配器类,执行特殊功能 //Target adapter = new Adapter(); // 继承被适配类,实现标准接口,方法中父类调用 Target adapter = new Adapter(new Adaptee()); // 直接实现标准接口,方法中通过被适配对象调用 adapter.request(); } }

    13、手撕简单工厂模式,枚举类

    注:还有工厂方法模式、抽象工厂模式 知乎:抽象工厂模式和工厂模式的区别? java设计模式之工厂模式

    package factory; /* 1、简单工厂模式或静态工厂模式:抽象产品、具体产品、通用工厂 2、工厂(方法)模式:抽象产品、具体产品、抽象工厂、具体工厂 3、抽象工厂模式,类似于上面的工厂模式, 有多个抽象产品(产品簇),工厂生产一整套即多个产品 * */ // 抽象可以是接口或抽象类 interface Fruit{ void desc(); } class Apple implements Fruit{ @Override public void desc() { System.out.println("this is apple..."); } } class Orange implements Fruit{ @Override public void desc() { System.out.println("this is orange..."); } } // 枚举类,定义形式 enum FruitTypeEnum{ // 核心,定义枚举实例,充当固定常量, 一般定义枚举实例都会加对应介绍 /* 如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。 而且 Java 要求必须先定义 enum 实例,且枚举类型的构造方法必须为私有方法。*/ APPLE(1, "apple"), ORANGE(2, "orange"); private int state; private String stateInfo; // 枚举类的本质就是提供有限个实例,因此构造器必须私有,不写也是默认私有 private FruitTypeEnum(int state, String stateInfo) { this.state = state; this.stateInfo = stateInfo; } /*后续的方法视需求情况而定*/ public int getState() { return state; } public String getStateInfo() { return stateInfo; } // 静态方法,拿到枚举对象 public static FruitTypeEnum stateOf(int state){ for(FruitTypeEnum fruitTypeEnum : FruitTypeEnum.values()){ if(fruitTypeEnum.state == state){ return fruitTypeEnum; } } return null; } } // 简单工厂类,扩展性查,增加水果种类,需要新增实现类并要更改工厂类方法 public class SimpleStaticFactory { // 简单工厂模式,create方法一般是static,也称为静态工厂 public static Fruit createFruit(FruitTypeEnum fruitTypeEnum){ Fruit fruit = null; switch(fruitTypeEnum){ // 这里为了复习枚举类 case APPLE: fruit = new Apple(); break; case ORANGE: fruit = new Orange(); break; default: fruit = new Apple(); } return fruit; } public static void main(String[] args) { Fruit fruit1 = createFruit(FruitTypeEnum.APPLE); fruit1.desc(); Fruit fruit2 = createFruit(FruitTypeEnum.stateOf(2)); fruit2.desc(); } }

    14、手撕装饰者模式

    package decorator; // 接口 public interface Shape { void draw(); } // 具体实现类 class Rectangle implements Shape{ @Override public void draw() { System.out.println("shape: rectangle"); } } class Circle implements Shape{ @Override public void draw() { System.out.println("shape: circle"); } } // 抽象装饰者 class ShapeDecorator implements Shape{ protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; } @Override public void draw() { decoratedShape.draw(); } } // 具体装饰者 class RedShapeDecorator extends ShapeDecorator{ public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { super.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape){ System.out.println("add border color : red"); } } // demo class DecoratedDemo{ public static void main(String[] args) { Shape circle = new Circle(); System.out.println("circle : with normal border"); circle.draw(); ShapeDecorator redCircle = new RedShapeDecorator(circle); ShapeDecorator rectangle = new RedShapeDecorator(circle); System.out.println("\ncircle : decorated circle"); rectangle.draw(); redCircle.draw(); } }

    负二、未理解部分

    1、面向对象或设计模式之六大原则

    JAVA设计模式总结之六大设计原则

    注:开单依里接迪特

    1、单一职责 一个类只负责一项职责,代码级别、方法级别

    2、里氏替换原则 原话:所有引用基类(父类)的地方必须能透明的使用其子类的对象 通俗:子类可以扩展父类的功能,但不能改变父类原有的功能。重写很容易碰到。

    3、依赖倒置原则(Dependence Inversion Principle) 面向接口 依赖于抽象,不要依赖于具体

    4、接口隔离原则(Interface Segregation Principle) 精简单一 做法是拆分接口,原因是:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上

    5、迪米特法则(最少知道原则) (Demeter Principle) 降低耦合 通俗:一个类对自己依赖的类知道的越少越好

    6、开闭原则(Open Close Principle) 对扩展开放,对修改关闭 用抽象构建框架,用实现扩展细节

    2、二十三种设计模式

    撒的发生的

    5、常见的序列化协议有哪些

    注:public interface Externalizable extends java.io.Serializable Java序列化,如何实现序列化和反序列化,常见的序列化协议有哪些?

    6、分布式系统中一致性哈希算法

    分布式系统中一致性哈希算法

    7、线程池的执行流程与参数

    线程池的工作原理与源码解读及各常用线程池的执行流程图

    8、JUC锁基于什么实现? AQS?

    java.util.concurrent JUC锁框架_ ReentrantLock原理分析 AbstractQueuedSynchronizer超详细原理解析 Java多线程系列–“JUC锁”01之 框架

    12、工厂模式、观察者模式、装饰器模式、设计模式分类的掌握

    设计模式分类:创建型模式,结构型模式,行为型模式 架构设计&分布式&数据结构与算法面试题(2020最新版)

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构 理解:抽象类实现一个接口,在抽象类中设置一个接口引用,重写接口方法但方法中仍调用原接口方法。套一个盒子而已。可以继承抽象类后添加具体的逻辑功能。

    一、Java基础

    1、String、StringBuilder、StringBuffer区别

    运行速度: StringBuilder > StringBuffer > String 注:两变一不变 线程安全: StringBuilder是线程不安全的,而StringBuffer是线程安全的

    2、Java多态

    定义:多态是同一个行为具有多个不同表现形式或形态的能力

    C++虚函数的存在是为了多态。

    Java 中其实没有虚函数的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。 如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。

    多态存在的三个必要条件: 继承或实现 重写 父类引用指向子类对象(注:这样只能调用公共方法,要想调用子类特有方法需要类型转换)

    3、Java-IO流

    Java-IO流

    4、怎么打破双亲委派

    怎么打破双亲委派 先前总结的双亲委派

    5、ThreadLocal

    ThreadLocal提供线程本地变量 ThreadLocal 的用法以及内存泄露(内存溢出)

    6、NIO详解(三):IO多路复用模型之select、poll、epoll

    select、poll、epoll之间的区别总结[整理] NIO详解(三):IO多路复用模型之select、poll、epoll 聊聊IO多路复用之select、poll、epoll详解

    二、Java并发

    1、CAS

    漫画:什么是CAS机制

    2、ThreadLocal内存泄漏分析与解决方案

    ThreadLocal 的用法以及内存泄露(内存溢出)

    3、Java并发——Executor框架详解(Executor框架结构与框架成员)

    Java并发——Executor框架详解(Executor框架结构与框架成员)

    三、JVM与GC

    1、Java内存泄漏的排查总结

    jstat -gcutil 本地虚拟机的唯一Id 1000(查询时间间隔) Java内存泄漏的排查总结

    2、

    四、数据库

    1、ACID

    Atomic(原子性):指整个数据库事务是不可分割的工作单位。只有使据库中所有的操作执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。

    Consistency(一致性):指数据库事务不能破坏 关系数据的完整性以及 业务逻辑上的一致性。例如对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNTS表中Tom和Jack的存款总额为2000元。

    Isolation(隔离性):指的是在并发环境中,当 不同的事务同时操纵 相同的数据时,每个事务都有各自的完整数据空间。

    Durability(持久性):指的是只要事务成功结束,它对数据库所做的更新就必须 永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

    五、mysql

    1、聚簇索引与非聚簇索引(也叫二级索引)

    聚簇索引与非聚簇索引(也叫二级索引)

    2、innodb引擎的4大特性

    innodb引擎的4大特性

    3、MySQL使用全文索引(fulltext index)

    MySQL使用全文索引(fulltext index)

    4、mysql 行级锁的使用以及死锁的预防

    mysql 行级锁的使用以及死锁的预防

    5、mysql视图

    mysql视图的作用(详细)

    6、MySQL 游标的使用

    MySQL 游标的使用

    7、mysql存储过程

    mysql存储过程学习笔记

    8、多表联合查询、连接查询、子查询

    【Mysql】多表联合查询、连接查询、子查询

    9、MySQL中 in 和 exists 区别

    MySQL中 in 和 exists 区别

    10、mysql-覆盖索引

    mysql-覆盖索引

    11、mysqldump和xtrabackup备份原理实现说明

    mysqldump和xtrabackup备份原理实现说明

    六、redis

    redis的持久化和缓存机制

    1、Redis中set类型的交集、并集、差集

    Redis中set类型的交集、并集、差集

    2、Redis:一致性Hash算法

    Redis:一致性Hash算法

    3、Redis与LRU

    Redis与LRU

    4、Reactor模式

    Reactor模式

    5、Bitmap和布隆过滤器

    大量数据去重:Bitmap和布隆过滤器(Bloom Filter) 漫画:什么是Bitmap算法? 分布式缓存击穿(布隆过滤器 Bloom Filter)

    6、Jedis与Redisson选型对比

    Jedis与Redisson选型对比

    7、Redis之Redis事务

    Redis之Redis事务

    七、spring框架

    Spring面试题(2020最新版)

    1、控制反转的理解

    IOC,把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。 所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,即IOC容器。

    对象之间很多存在依赖关系,麻烦 IOC容器 创建并管理对象,同时维护依赖关系 解耦,由容器去维护具体的对象 托管类的产生,如代理,只关心使用,不关心如何生成

    2、依赖注入的理解

    依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。 组件不做定位查询,即组件只提供普通的Java方法让容器去决定依赖关系。

    3、IOC容器和依赖注入Dependency Injection关系

    IOC控制反转 Inversion of control 上层建筑依赖下层建筑 IOC容器会从当前层逐层往下直到底找config,从底层往上注入 DI注入,4种,Setter注入、构造器Constructor注入、接口注入 、注解注入(与注入区分开) 注:其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃

    Spring将管理对象称为Bean,组件

    spring core和spring context

    spring beans:提供了BeanFactory(接口)

    BeanFactory和ApplicationContext(仍是接口并继承了更多接口)

    3、Spring 框架中都用到了哪些设计模式

    工厂模式:BeanFactory 单例模式:Bean默认为单例模式 代理模式AOP

    模板方法RestTemplate

    观察者模式ApplicationListener

    4、BeanFactory和ApplicationContext的区别以及关系

    依赖关系、加载方式、创建方式、注册方式

    BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例

    ApplicationContext 可以称之为 “高级容器”,代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。

    5、ApplicationContext通常的实现

    ClassPathXmlApplicationContext 类路径

    FileSystemXmlApplicationContext 和WebXmlApplicationContext

    6、Spring Bean作用域

    singleton(默认) 、prototype request、session、global-session 后三种基于web的Spring ApplicationContext情形下有效

    7、单例bean是线程安全的吗以及如何处理线程并发问题

    不是, 实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了

    在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

    8、解释Spring框架中bean的生命周期

    主要是:实例化+填充属性(值和bean的引用注入到bean对应的属性中)+。。。

    bean装载到Spring应用上下文中,将一直驻留在应用上下文中,直到该应用上下文被销毁。当然也可以提前销毁。

    bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。对应的注解(@PostConstruct和@PreDestroy)

    9、自动装配

    分为xml中自动装配和注解@Autowired自动装配

    注解@Autowired: 首先根据bean类型,多个相同bean类型实例则根据名称,仍找不到报异常

    10、AOP的理解

    AOP,即将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等

    AOP织入方式三种,编译时织入(静态代理)、类加载织入、运行时织入(动态代理,Spring采用这种)

    静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理

    11、JDK动态代理和CGLIB动态代理

    JDK动态代理只提供接口的代理,不支持类的代理。

    CGLIB(Code Generation Library),通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

    Spring的aop代理,先去查看当前类是否有接口,有接口就去JdkDynamicAopProxy(config)代理,没有就去ObjenesisCglibAopProxy(config)代理

    12、5种通知,后置通知与返回通知的区别

    前置、 后置(不论该方法是否异常都执行)、 返回(在方法正常结束时执行,可以访问到方法的返回值)、 异常(可以访问到异常对象,且可以指定在出现特定异常时再执行)、 环绕(需携带ProceedingJoinPoint类型参数,类似动态代理中的全过程或可实现前面的4个通知,必须有返回值)

    13、AOP的切入点和连接点的区别以及关注点和横切关注的区别

    连接点,代表具体的一个方法的执行或者认为程序执行的点 Spring AOP只支持方法级别的连接点。方法之外的连接点拦截功能,我们可以利用Aspect来补充。 暂时理解是细粒度不够高,但一般够用

    切入点,匹配通知所要织入的一个或多个连接点或者认为是匹配很多连接点的断言或者表达式

    关注点,具体某个想实现的功能, 横切关注点,整个应用都可能会使用

    14、spring 的事务隔离

    spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致 即多了个和数据库同样的隔离配置而已,不算真正的5个隔离级别

    15、Spring支持的事务管理类型

    spring编程式事务管理的环境搭建及实例 编程式事务管理:通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。

    声明式事务管理:可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务

    16、Spring的事务传播行为

    没懂

    17、@Component, @Controller, @Repository, @Service 有何区别

    @Required 注解,表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配。若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。

    @Autowired和@Resource之间的区别: @Autowired默认是按照类型装配注入的 @Resource默认是按照名称来装配注入的

    @Bean注解,它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文

    @Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。

    @Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。

    @Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。

    @Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

    Processed: 0.015, SQL: 9