参考资料
spring官网
中文文档翻译
参考文章:https://www.zhihu.com/question/39814046/answer/2084678610
spring使用了那些设计模式
单例模式:Spring 中的 Bean 默认情况下都是单例的。
工厂模式:工厂模式主要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象
代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理。
模板方法模式:主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。
IOC和AOP的概念
IOC:控制反转,指的是将创建对象的权力交给了spring框架。通过spring来管理对象的创建、配置和生命周期。不需要人工来管理对象之间复杂的依赖关系,这样做的好处就是解耦。spring主要提供了BeanFactory和ApplicationContext两种IOC容器,通过他们来实现Bean的管理。
ApplicationContext是BeanFactory的子类。
AOP:叫做面向切面编程,他是一个编程范式,目的就是提高代码的模块性。Spring Aop基于动态代理的方式实现,如果是实现了接口的话就会使用JDK动态代理,反之则使用CGLIB代理,可以实现对业务逻辑的隔离,提高代码的模块能力,也能达到解耦的目的。Spring主要提供了Aspect切面、JoinPoint连接点、PointCut切入点、Advice增强等实现方式。
JDK动态代理和CGLIB代理的对比
JDK动态代理主要是针对类实现某个接口,AOP则会使用JDK动态代理。它是基于反射的机制实现,生成一个实现相同接口的代理类,然后通过重写方法的方式,实现对代码的增强。
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行
的目标对象方法作为参数传入
**/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK 代理开始~~");
//反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK 代理提交");
return returnVal;
}
});
}
如果某个类没有实现接口,AOP则会使用CGLIB代理。他的底层原理是基于asm第三方框架,通过修改字节码生成一个子类,然后重写父类的方法,实现对代码的增强。
FactoryBean和BeanFactory的区别
BeanFactory是Bean的工厂,ApplicationContex的父类,IOC容器的核心,负责生产和管理Bean对象。
FactoryBean是Bean对象,可以实现FactoryBean接口定制实例化Bean的逻辑,通过代理一个Bean对象,对方法前后做一些操作。
Spring Bean的生命周期
SpringBean 生命周期简单概括为4个阶段:
1.实例化,创建一个Bean对象
2.填充属性,为属性赋值
3.初始化
4.如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源(例如:实现ServletContextAware接口可以拿到servletContext对象)
5.如果实现了BeanPostProcessor接口,则会回调该接口postProcessBeforeInitialzation和postProcessAfterInitialization方法
6.如果配置了init-method方法,则会执行init-method配置的方法
7.销毁
8.容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法
9.如果配置了destroy-method方法,则会执行destroy-method配置的方法
Spring是怎么解决循环依赖的
首先,Spring 解决循环依赖有两个前提条件:
不全是构造器方式的循环依赖(将实例化和初始化分开)
必须是单例(确保用的是同一个对象)
基于上面的问题,我们知道Bean的生命周期,本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化完全的对象。
第一级缓存:用来保存实例化、初始化都完成的对象。
第二级缓存:用来保存实例化完成,但是未初始化完成的对象。
第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象。
图解步骤说明参考:https://www.zhihu.com/question/39814046/answer/2084678610