动态代理
- JDK 动态代理 使用JAVA反射包中的类和接口实现动态代理的功能,JAVA.lang.reflect包;主要是三个类:
InvocationHandler,Method,Proxy;
CGLIB动态代理,第三方工具类库,创建代理对象,cglib的原理是继承,通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改
注意:cglib是继承,重写方法,所以要求目标类不能是final修饰的,方法也不能是final的,cglib的要求目标类比较宽松,只要继承就可以了,cglib在很多的框架中使用,比如mybatis,spring框架中都有使用
JDK动态代理
-
Method类表示方法,目标类的方法;通过Method可以执行某个目标类的方法 Method.invoke();
-
InvocationHandler接口(调用处理器) 就一个方法Invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
-
Proxy类:核心的对象 创建代理对象
@param ClassLoader 目标类加载器 getClass().getClassLo ader()
@param interfaces 接口 目标类实现的接口 也是反射获取的
@param InvocationHandler 代理类要完成的功能 我们自己写的
@return 目标对象的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){}
AOP
Spring三级循环依赖
三级缓存是如何避免循环依赖
@Autowired(类型注入),@Resource(名称注入) 注解依赖注入如何避免循环依赖
如果存在循环依赖,即 Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A,则 Spring 会先创建 Bean A,并将其注入到 Bean B 中的代理对象中,然后再创建 Bean B,并将代理对象注入到 Bean A 中。代理对象可以避免循环依赖问题,因为它并不是完整的 Bean 实例,而是一个动态生成的代理对象,只有在真正需要使用 Bean 实例时才会触发创建。
AOP过程中生成的代理对象是谁管理的
AOP 产生的代理对象实际上是 Bean 实例的一种,因此代理对象会被放到 IOC 容器中管理。但是,代理对象并不是通过三级缓存来管理的,而是通过 BeanPostProcessor 接口来创建和管理的
**BeanPostProcessor 接口是 Spring 中非常重要的接口之一,**它定义了在 Bean 创建过程中的两个回调方法:postProcessBeforeInitialization() 和 postProcessAfterInitialization()。在 Bean 创建过程中,当 Spring 创建一个 Bean 实例后,会先调用 postProcessBeforeInitialization() 方法,然后再调用 postProcessAfterInitialization() 方法。
代理对象直接替换掉原来的bean吗
在 Spring 中,AOP 产生的代理对象是通过 BeanPostProcessor 接口来创建和管理的。当 Spring 创建一个 Bean 实例时,如果该 Bean 需要使用 AOP,会先创建一个代理对象,然后将代理对象注入到 Bean 实例中。
具体来说,代理对象的注入过程分为以下几个步骤:
- Spring 通过 BeanPostProcessor 接口的 postProcessAfterInitialization() 方法创建代理对象。
- Spring 将代理对象作为参数传递给 postProcessAfterInitialization() 方法,同时也会将 Bean 的名称和类型等信息传递给该方法。
- 在 postProcessAfterInitialization() 方法中,如果需要创建代理对象,则可以使用 Spring 提供的 AOP API(例如 ProxyFactoryBean)来创建代理对象,并将其注入到 Bean 实例中。
- Spring 将代理对象注入到 Bean 实例中,替换原来的 Bean 实例。
原来的 Bean 实例已经完成了所有的初始化工作(包括属性注入、生命周期回调等),而代理对象则是在这个基础上进行的增强。因此,在使用 AOP 时,需要确保代理对象的增强不会影响到 Bean 实例的初始化和生命周期回调等操作
Bean容器与三级缓存容器的相关
Bean 实例是按照名称或类型进行管理的。
存放 Bean 的容器和三级缓存的三个容器虽然都是 Map 集合,但是它们的作用和管理方式是不同的。存放 Bean 的容器是用于管理所有 Bean 实例的,它负责创建和管理 Bean 实例,并将 Bean 实例按照名称或类型进行分类和管理。而三级缓存则是用于解决循环依赖问题的,它只在出现循环依赖时才会被使用。
在 Spring 中,存放 Bean 的容器和三级缓存的三个容器之间的关系可以简单描述如下:
- 当 Spring 创建一个 Bean 实例时,首先会检查该 Bean 实例是否已经被创建。如果该 Bean 实例已经被创建,则直接从存放 Bean 的容器中获取该 Bean 实例,否则进入下一步。
- 如果该 Bean 实例还未被创建,则会检查该 Bean 实例是否处于循环依赖中。如果该 Bean 实例处于循环依赖中,则会将该 Bean 实例放入三级缓存中的第一个 Map 集合中,否则进入下一步。
- 如果该 Bean 实例既不处于循环依赖中,也没有被创建过,则会创建该 Bean 实例,并将其放入存放 Bean 的容器中进行管理。
三级缓存解决了循环依赖之后,会生成bean实例
总之,在 Spring 中,三级缓存最终会生成 Bean 实例。当一个 Bean 实例处于循环依赖中时,Spring 会将其放入三级缓存中的第一级缓存中,并在后续的处理中逐步生成该 Bean 实例。三级缓存中的 Bean 实例是按照依赖关系顺序进行创建的,并最终被放入存放 Bean 的容器中进行管理。需要注意的是,不是所有的 Bean 实例都会进入三级缓存中,只有处于循环依赖中的 Bean 实例才会进入三级缓存。
可以理解为三级缓存只是暂时的缓存bean示例工具,最后解决完依赖注入之后,将bean放回到bean容器中
三级缓存只是 Spring 中用于解决循环依赖问题的一个临时工具,它并不是用来管理所有的 Bean 实例的。当 Spring 创建 Bean 实例时,如果发现该 Bean 实例处于循环依赖中,就会将该 Bean 实例放入三级缓存中,在后续处理中逐步生成该 Bean 实例。当所有的 Bean 实例都创建完成后,Spring 会将它们放入存放 Bean 的容器中进行管理。
需要注意的是,三级缓存只是一个暂时的缓存工具,它并不是用来管理 Bean 实例的长期存储工具。一旦 Bean 实例被创建成功并放入存放 Bean 的容器中进行管理,它们就不再需要被存储在三级缓存中了。因此,在 Spring 中,三级缓存只是一个用于解决循环依赖问题的辅助工具,其生命周期和作用范围是有限的。
Bean容器
Bean 容器的构造实际上是由 ApplicationContext 接口的实现类来完成的。ApplicationContext 接口是 Spring 中应用上下文的核心接口,它继承了 BeanFactory 接口,提供了更多的功能,例如国际化支持、事件传播、应用上下文层次结构等
ApplicationContext 接口的实现类的构造过程一般包括以下几个步骤:
-
解析配置文件:ApplicationContext 接口的实现类需要解析配置文件,将配置文件中定义的 Bean 实例信息解析成相应的 Java 对象,例如 BeanDefinition 对象等。
-
创建 Bean 实例:ApplicationContext 接口的实现类需要根据配置文件中定义的 Bean 实例信息,创建相应的 Bean 实例。这个过程一般包括 Bean 实例化、属性注入、生命周期回调等步骤。
-
注册 Bean 实例:ApplicationContext 接口的实现类需要将创建好的 Bean 实例注册到 Bean 容器中。在注册 Bean 实例时,需要将 Bean 实例按照名称或类型进行分类和管理。
-
处理 Bean 实例之间的依赖关系:ApplicationContext 接口的实现类需要处理 Bean 实例之间的依赖关系。这个过程一般包括解析依赖关系、查找依赖对象、注入依赖对象等步骤。
-
初始化容器:ApplicationContext 接口的实现类需要初始化容器,包括初始化事件监听器、初始化 AOP 相关的对象、初始化国际化相关的对象等。
-
启动容器:ApplicationContext 接口的实现类需要启动容器,使得容器能够开始工作。在启动容器时,需要完成容器的预处理、事件监听器的注册、AOP 代理的生成等步骤。
ApplicationContext 接口的实现类可以有多种方式来完成 Bean 容器的构造。例如,ClassPathXmlApplicationContext 类可以使用 XML 配置文件来构造 Bean 容器;AnnotationConfigApplicationContext 类可以使用 Java 配置类来构造 Bean 容器;WebApplicationContext 接口的实现类可以在 Web 应用程序中构造 Bean 容器等。不同的实现方式可能会有一些细节上的差异,但是它们的基本构造过程都是类似的。
IOC
spring的IOC是通过什么实现的?
pring中IOC的实现主要是由
BeanFactory
和ApplicationContext
这两个核心接口以及它们的多个实现类来完成的。
BeanFactory
是IOC容器的基础接口,提供了最基本的IOC功能,例如根据名称或类型获取bean等。ApplicationContext
在BeanFactory
的基础上增加了更多的企业级功能,例如国际化支持、事件驱动、AOP等。它是Spring应用程序中使用最广泛的容器。在具体实现上,Spring IOC的核心代码在
spring-core
模块中,其中通过XmlBeanDefinitionReader等类对XML配置文件进行解析,并将解析结果存储在BeanDefinition对象中,然后将BeanDefinition对象注册到IOC容器中。当应用程序需要访问某个bean时,IOC容器根据BeanDefinition信息创建相应的bean并返回给应用程序。除了XML配置方式外,Spring还支持注解和Java配置方式来定义bean,从而更加灵活地满足不同场景下的需求。