Spring 5





基本概念

Spring的XML解析原理



Spring​的作用:


  • 定位:​ 寻找​XML​配置文件
  • 加载:​ 将解析的​XML​配置加载到内存
  • 实例化:​ 根据加载的​XML​配置进行实例化
    Java架构师Day02-源码分析之Spring5_Java



IOC体系图:


  • 所有的​IOC​都有继承关系,这样设计使得任何一个子类​IOC​都可以直接使用父类​IOC​加载的​Bean
  • 其中重要的类是​BeanFactory​和​ApplicationContext​,这是所有​IOC​的父接口


    • BeanFactory​中提供了对于​Bean​最基本的操作
    • ApplicationContext​继承​BeanFactory,​ 同时继承​MessageSource, ResourceLoader, ApplicationEventPublisher​接口用来提供国际化,资源加载,时间发布高级功能 ​.Spring​加载的​XML​的类是​ApplicationContext​的子类


  • 其余重要的类:


    • BeanFactory


      • HierarchicalBeanFactory
      • ListableBeanFactory

        • DefaultListableBeanFactory

      • AliasRegistry

        • SimpleAliasRegistry



    • ResourceLoader

      • ApplicationContext

        • AbstractApplicationContext

          • AbstractRefreshableApplicationContext

            • AbstractRefreshableConfigApplicationContext

              • AbstractXmlApplicationContext

                • ClassPathXmlApplicationContext











Spring中的两种标签:​ 标签在使用前都需要在​Spring​的​xml​配置文件里声明​Namespace URI,​ 这样才能在解析标签时通过​Namespace URI​找到对应的​NamespaceHandler


  • Spring原生标签:​ 不带前缀的标签是​Spring​中的原生标签
  • 自定义标签:​ 带前缀的标签是自定义标签



<bean class="com.oxford.bean.Bean" id="bean" c:id="beanId" p:name="beanName" />

  • c:​ 通过构造器给属性赋值,是​constructor-arg​的简化写法
  • p:​ 通过属性的​setter​方法给属性赋值,是​property​的简化写法
  • Spring自定义扩展标签:


    • 创建一个自定义标签和解析类
    • 指定命名空间和​NamespaceHandler
    • 在​META-INF​的​spring.handler​文件中指定命名空间和​NamespaceHandler​的映射关系. 类似​Spring​的​c​标签和​p​标签一样

http://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler

Spring的XML解析流程:Java架构师Day02-源码分析之Spring5_Java_02

Spring的Bean实例化原理


  • BeanFactoryPostProcessor的类图:Java架构师Day02-源码分析之Spring5_Spring_03

    • ConfigurationClassPostProcessor​类完成对 ​@Configuration, @Bean​等注解的解析注册
    • FactoryMethod​用于创建对象
    • 可以获取 ​@Autowired​注解标记的构造函数并且通过这些构造函数进行实例化


  • BeanPostProcessor​接口的继承体系:
    Java架构师Day02-源码分析之Spring5_源码_04
  • BeanPostProcessor​接口是​Spring​的一个重要的扩展点,包含两个方法:
@Nullable
default Object postProcessBeforeInitialization() throws BeanException {
return bean;
}

@Nullable
default Object PostProcessAfterInitialization() throws BeanException {
return bean;
}
  • 实现了​BeanPostProcessor​接口的对象会在实例化之前和之后调用这两个方法

Bean​对象的创建包含以下几个工作:

  • 初始化实例
  • 解析 ​@PostConstruct, @PreDestroy, @Resource, @Autowired, @Value​等注解
  • 依赖注入
  • 调用​BeanPostProcessor​的方法
  • AOP​入口


Bean​对象的实例化:

  • 在​Bean​对象实例化过程中获取所有标注 ​@Autowired​注解的构造函数就是通过调用​autowireConstructor​来进行实例化
  • 具体就是委托给​ConstructorResolver​类来进行处理,包括​factoryMethod​创建对象也是委托​ConstructorResolver​类进行处理
  • 如果没有标注 ​@Autowired​注解的构造函数就会调用​instantiateBean()​ 方法,利用无参构造函数去创建对象并返回,这种方式也是大部分对象实例化的方式


Bean实例化过程分析:

  • ApplicationContextAwareProcessor​中对接口​ApplicationEventPublisherAware​和接口​ApplicationContextAware​的调用
  • InitDestroyAnnotationBeanPostProcessor​中对 ​@PostConstruct​注解方法的调用
  • ImportAwareBeanPostProcessor​中对​ImportAware​类型实例​setImportMetadata​调用
  • invokeInitMethods()​ 方法中对​InitializingBean​接口中的​afterPropertiesSet()​ 方法和​init-method​属性配置的初始化方法进行调用
  • applyBeanPostProcessorAfterInitialization()​ 方法中对​BeanPostProcessor​的​postProcessAfterInitialization()​ 方法进行调用
    Java架构师Day02-源码分析之Spring5_spring_05



Beans

接口实例化

基本概念


  • JavaBean:
  • JavaBean​是遵循​Sun​制定的​JavaBean​标准的特定编码规范的类:

  • 包含一个默认的公有无参构造器
  • 允许通过​getter​和​setter​访问器访问类的成员属性,或者其余遵循特定命名规范的方法访问
  • 实现了​java.io.Serializable​接口,可序列化

  • POJO:

  • POJO​即简单​Java​对象
  • POJO​类的对象不需要通过框架来使用,也不需要在特定的应用服务环境下运行
  • POJO​主要用来区分简单​Java​对象,轻量级​Java​对象和重量级​Java​对象

  • SpringBean:

  • SpringBean​表示由​Spring​框架管理的对象,也就是由​Spring​框架的容器进行初始化,配置和管理的​Java​对象
  • Spring Bean​是通过​Spring​配置文件或者通过注解定义的,在​Spring​容器中初始化,然后注入到应用程序中


Spring实例化Bean

  • Spring寻找并解析Bean属性的方式:

  • 注解的方式:

  • Spring​在启动后进行初始化时会扫描​classpath​包下符合要求的​class
  • 然后进行解析并注册到​BeanFactory​中

  • xml的方式:
  • 注解通过​XmlBeanDefinitionReader​解析​Bean
  • 一般情况下,主流的方式是使用注解的配置,尤其是在​SpringBoot​框架中

构造器实例化


  • SpringBean类中的默认构造器创建​Bean​实例:

  • Spring​容器根据​Spring​配置文件的路径加载配置文件
  • 在加载的同时 ​,Spring​容器会通过实现​Bean​类中默认的无参构造器对​Bean​进行实例化

静态工厂实例化


  • 工厂实现类中提供一个静态工厂方法创建​Bean​实例:

  • Spring​容器根据​Spring​配置文件的路径加载配置文件
  • 在加载的同时 ​,Spring​容器会通过工厂实现类​StaticFactoryBean​类中的静态方法​getBean()​ 对​Bean​进行实例化

实例工厂实例化


  • 工厂实现类直接使用成员方法创建​Bean​实例,同时在配置文件中:

  • 需要实例化的​Bean​不是通过​class​属性直接指向实例化的类
  • 而是通过​class​属性配置实例工厂
  • 然后通过​factory-bean​属性指定一个实例工厂
  • 最后使用​factory-method​属性指定使用​factory-bean​配置的实例工厂中的哪一个方法

  • Spring​容器根据​Spring​配置文件的路径加载配置文件
  • 在加载的同时 ​,Spring​容器会通过配置的实例工厂类​InstanceBeanFactory​中的成员​getBean()​ 对​Bean​进行实例化


代理Bean操作


  • 实现一个动态代理接口,并且在​Spring​容器初始化完成之前将该代理对象注册到​Spring​容器中.实现可以通过 ​@Autowired​等方法从​Spring​中获取该代理对象
  • ​Spring中代理Bean操作示例​

Spring中动态注入和删除Bean


  • 动态注入和删除Bean:

  • 使用​getBean()​ 获取对象的操作,这些对象都是程序中事先定义好的
  • 有时候需要动态地加入和删除对象. 尽管可以采用配置文件或者注解的方式,但是每次都需要重启服务
  • 为了避免以上问题,需要在​Spring​中对​Bean​进行动态地管理,包括​Bean​对象的注入和删除

  • Spring中动态管理Bean实现思路:

  • Spring​中管理​Bean​对象的是​BeanFactory,​ 具体的是​DefaultListableBeanFactory
  • 通过获取到​Bean​类的​ApplicationContext​对象获取到​BeanFactory
  • 在类​DefaultListableBeanFactory​中有​registerBeanDefinition()​ 方法使用一个​BeanDefinition​参数注入​Bean
  • 通过​BeanDefinitionBuilder​可以构建一个​Bean​类的​BeanDefinition

  • Spring​中动态注入​Bean​步骤:

  • 获取​Bean​类的​ApplicationContext
  • 通过​ApplicationContext​获取​BeanFactory
  • 通过​BeanDefinitionBuilder​获取​Bean​类的​BeanDefinition
  • 通过​BeanFactory​的​registerBeanDefinition()​ 注入​Bean​类的​BeanDefinition
  • 注入完成后,可以通过​ApplicationContext​的​getBean()​ 获取​Bean​对象


// 1. 获取Bean类的ApplicationContext
ApplicationContext ctx = SpringApplication.run(Bean.class, args);
// 2. 通过ApplicationContext获取BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
// 3. 获取并创建BeanDefinition
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Bean.class);
beanDefinitionBuilder.addPropertyValue("name", "Oxford");
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 4. 通过BeanFactory的registerBeanDefinition()注入Bean类的BeanDefinition
defaultListableBeanFactory.registerBeanDefinition("beanInterface", beanDefinition);
// 获取动态注册的Bean
Bean beanInterface = ctx.getBean(Bean.class);
  • Spring​中动态删除​Bean​步骤:

  • 获取​Bean​类的​ApplicationContext
  • 通过​ApplicationContext​获取​BeanFactory
  • 通过​BeanFactory​的​removeBeanDefinition()​ 删除已经注入的​Bean​类的​BeanDefinition

// 1. 获取Bean类的ApplicationContext
ApplicationContext ctx = SpringApplication.run(Bean.class, args);
// 2. 通过ApplicationContext获取BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
// 通过BeanFactory的removeBeanDefinition()删除已经注入的BeanDefinition
defaultListableBeanFactory.removeBeanDefinition("beanInterface");
  • 动态注入Bean出现的问题:
  • ​// 使得Bean对象完成Spring初始化过程中的所有增强器检验,但是不重新创建Bean对象 applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(beanClass, beanClass.getClass().getName()); // 将Bean对象以单例的形式注入到容器中. 此时通过 beanClass.getClass() 和 beanClass.getClass().getName() 都可以获取到Spring容器中注入的Bean对象 defaultListableBeanFactory.registerSingleton(beanClass.getClass().getName(), beanClass); ​

  • 多次注入同一个​Bean​类时,如果​BeanName​一样,后注入的​Bean​会覆盖先注入的​Bean
  • 多次注入同一个​Bean​类时,如果​BeanName​不一样,就会产生两个​Bean


    • 此时不能使用​ApplicationContext.getBean(Bean.class)​ 方法通过​ByType​方式获取注入的​Bean,​ 会产生报错
    • 此时可以使用​ApplicationContext.getBean(“beanInterface”)​ 方法通过​ByName​的方式获取重复注入的​Bean


  • 可以使用以下单例方式解决重复注入​Bean​的问题:

AOP


  • AOP:Aspect-oriented programming.​ 面向切面的程序设计

  • 将横切关注点进一步分离,以提高代码的模块化程度
  • 在现有的项目代码的基础上增加额外的通知​Advice​机制,能够对声明为切点​Pointcut​的逻辑功能代码块进行统一的管理与装饰
  • 横切关注点:​ 在项目的多个模块中都有出现的逻辑功能代码
  • 面向切面的程序设计可以将与代码核心业务逻辑联系较弱的功能添加到程序中,同时保证业务代码的可读性

  • AOP​核心思想:
  • 从核心关注点分离出横切关注点是面向切面程序设计的核心

  • 分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来
  • 业务逻辑中不再含有针对特定领域问题代码的调用
  • 业务逻辑和特定领域问题的关系通过切面来进行封装和维护

  • AOP和OOP的比较:

  • OOP:​ 面向对象的程序设计

  • OOP​引入了​封装,继承和多态​来建立一个对象层次结构来模拟公共行为的集合.但是​OOP​无法为分散的对象引入公共行为
  • OOP​适用于定义对象自上而下的关系,不适合定义对象从左到右的关系

  • AOP:​ 面向切面的程序设计

  • 使用横切的技术,分解封装对象的内部,将影响多个类的公共行为封装到一个可重用的模块称作切面
  • AOP​通过横切的关系将与业务无关,但是被业务模块共同调用的逻辑和责任封装起来,减少项目中的重复代码,降低模块之间的耦合度,提升项目的操作性和维护性


  • AOP中的基本概念:

  • 切面:​ AspectJ
  • 模块化的横切关注点.也就是横向分散在多个功能模块中的特定逻辑功能
  • 连接点:​ Join point

  • 在项目执行过程中能够在项目中插入切面功能的项目中的某一个点
  • Spring AOP​中​Joinpoint​指代的是所有方法的执行点
  • 这个点可以是项目中某个方法调用前,调用后,方法抛出异常后等等
  • 切面利用这些连接点切入到正常的项目流程中,添加某些行为
  • AOP​中的​Joinpoint​可以有多种类型:

  • 构造方法调用
  • 字段的设置和获取
  • 方法的调用
  • 方法的执行
  • 异常处理的执行
  • 类的初始化
  • 注意:​ Spring中只支持执行方法类型的joinpoint


  • 通知:​ Advice

  • AOP​框架在特定的连接点处执行的动作
  • Spring AOP​中提供​5​种类型的通知​Advice:

  • 前置通知:​ Before. 在目标方法调用之前执行通知功能
  • 后置通知:​ After. 在目标方法调用完成之后执行通知功能.无论目标方法是否发生异常,后置通知都会执行
  • 后置返回通知:​ After-returning. 在目标方法返回值之后执行通知功能
  • 后置异常通知:​ After-throwing. 在目标方法抛出异常之后执行通知功能
  • 环绕通知:​ Around. 在目标方法调用之前和调用之后执行通知功能


  • 切点:​ Pointcut

  • 执行通知的一系列连接点的集合
  • Pointcut​是一个描述信息,用于修饰​Joinpoint,​ 通过​Pointcut,AOP​就可以确定哪些​Joinpoint​可以编织进入​Advice
  • AOP​通过切点定位到特定的连接点
  • 一个切点匹配多个连接点

  • 引入:​ Introduction

  • 添加方法或者字段到被通知的类
  • Spring​支持引入接口到任何被通知的对象中
  • Spring​中使用​Introduction,​ 可以通过​DelegatingIntroductionInterceptor​来实现通知,通过​DefaultIntroductionAdvisor​来配置​Advice​和代理类要实现的接口

  • 目标对象:​ Target Object
  • 包含连接点的对象.也就是被通知或者被代理的对象
  • AOP代理:​ AOP Proxy

  • AOP​框架创建的对象,包括通知
  • Spring​中的​AOP​代理包括​JDK​动态代理和​CGLIB​代理

  • 织入:​ Weaving
  • 织入描述的是将切面应用到目标对象来创建新的代理对象的过程

  • Spring AOP​使用了动态代理技术,在项目运行时织入切面
  • Spring AOP​支持使用两种方式​JDK​动态代理和​CGLIB​代理生成代理对象.默认策略是如果目标类为接口,则使用​JDK​动态代理,如果目标类是一个类对象则使用​CGLIB​代理


  • AOP实现的两种方式:

  • 动态代理方式:​ 利用拦截方法,对拦截方法进行装饰,取代原有方法的执行
  • 静态织入方式:​ 引入特定的语法创建切面,使得编译器在编译期间织入切面的代码

  • AOP​使用的四种方式:

  • 基于代理模式的​AOP​使用
  • @AspectJ​注解驱动的切面
  • POJO​切面,通过 ​<aop:config />​ 配置切面
  • 注入式​AspectJ​切面,通过 ​<aop:aspectj-autoproxy />​ 配置切面

  • Spring AOP的使用方法有以下三个步骤:

  • 定义增强方法,并在方法里使用​AspectJ​的注解标注​Spring​在何处调用方法
  • 在横切方法上使用注解 ​@Component​和 ​@Aspect
  • 在 ​@Configuration​配置类上使用注解 ​@EnableAspectJAutoProxy


  • modifier-pattern:​ 修饰符匹配
  • return-type-pattern:​ 返回值匹配
  • declaring-type-pattern:​ 类路径匹配
  • name-pattern:​ 方法名匹配
  • param-pattern:​ 参数匹配
  • throws-pattern:​ 异常类型匹配
  • ? :​ 表示该匹配项是可选项
  • 示例:
  • ​execution(* *(..)) ​
  • execution(public * com.oxford.service.*(..))
  • execution(* com.oxford.service..*.*(..))
  • 匹配​com.oxford.service​包以及子包下面的所有方法:
  • 使用 ​@Pointcut​定义切点时,可以使用 ​&&, ||​ 和 ​!​ 逻辑运算符


面向切面的基础


  • 面向切面程序设计的核心概念就是从核心关注点中分离出横切关注点:

  • 分离关注点使得解决特定领域问题的逻辑功能代码从业务逻辑代码中独立出来
  • 业务逻辑代码中不再含有对特定领域问题的逻辑功能代码的调用
  • 业务逻辑代码同对特定领域问题的逻辑功能代码的关系通过切面来进行封装和维护

  • 关注点:​ Concern

  • 对软件工程有意义的,小的,可管理的,可描述的软件组成部分
  • 一个关注点通常只和一个特定概念或者目标相关联

  • 主关注点:​ Core Concern
  • 一个软件中的最主要的关注点
  • 关注点分离:​ Separation of concerns, SOC
  • 标识,封装和操作关注点的能力
  • 方法:​ Method
  • 用来描述,设计和实现一个给定关注点的软件构造单位
  • 横切:​ Crosscut
  • 如果实现两个关注点方法存在交集,那么这两个关注点相互横切
  • 支配性分解:​ Dominant decomposition

  • 将软件分解成模块的主要方式

  • 传统的程序设计语言以一种线性的文本来描述软件,只采用一种方式,比如类来将软件分解成模块
  • 这样使得某些关注点比较好捕捉,容易进一步组合,扩展
  • 但是仍然会存在一些关注点没有被捕捉,弥撒在整个软件内部

  • 支配性分解通常是按照主关注点进行模块分解的

  • 横切关注点:​ Crosscuting concerns

  • 在传统的程序设计语言中,除了主关注点可以被支配性分解的方式捕捉外,仍然有许多没有被支配性分解方式捕捉到的关注点
  • 这些关注点弥散在整个软件内部,这些关注点同主关注点是横切的

  • 切面:​ Aspect

  • 支配性分解的基础上提供的一种辅助的模块化机制
  • 切面的模块化机制可以捕捉横切关注点


AOP原理剖析

Java架构师Day02-源码分析之Spring5_spring_06


  • 后置处理器根据​Bean​是否配置​Advisor​判断是否需要进行动态代理
  • 如果需要进行动态代理,那么就构造创建​ProxyFactory​对象
  • 通过​ProxyFactory​对象的父类中的​getAopProxyFactory()​ 方法获取​AopProxyFactory​对象,默认获取的是​DefaultAopProxyFactory
  • 通过​AopProxyFactory​工厂​createAopProxy()​ 方法创建实际的代理对象
  • ProxyBeanFactory:

Java架构师Day02-源码分析之Spring5_源码_07

  • Spring​使用工厂模式创建每一个​Proxy.​ 每一个​Class​类型,都会有一个相对应的​ProxyFactoryBean

  • 对于生成​Proxy​的工厂而言,只需要知道对应的​Advice​信息即可
  • Advice​信息维护在​Advised​中 ​,Advised​可以根据特定的类名和方法名返回对应的​AdviceChain,​ 来表示需要执行的​Advice​串

Java架构师Day02-源码分析之Spring5_Java_08


  • JDK动态代理:

  • JDK​动态代理是面向接口的​JdkDynamicAopProxy​生成代理对象

  • 溯源到​JDK​动态代理的字节码文件.在反编译的代码文件中可以发现代理类已经是继承了​Proxy​类,因为​Java是单继承多实现​的,所以不能再继承其余的类,但是代理类与目标类之间必须建立一种关系来保证代理对象可以被引用到,这样就只能实现接口
  • 目标类实现了至少一个接口时,那么代理类就可以通过实现与目标类相同的接口,使用接口类型的变量接收代理类的实例

  • JdkDynamicAopProxy​类实现了​AopProxy,​ 返回​Proxy,​ 并且自身也实现了​InvocationHandler
  • 也就是说,当我们使用​proxy​时,对​proxy​对象调用的方法,都会转到这个类的​invoke()​ 方法中

  • Cglib代理:
  • 基于​Cglib​子类继承方式​CglibAopProxy​生成代理对象

Spring AOP代理选择

代理描述

实现机制

优点

JDK动态代理

1. 通过反射接受被代理的类,并且要求被代理的类必须实现一个接口

2. JDK动态代理的核心是InvocationHandler接口和Proxy类

通过Java的内部反射机制实现

反射机制在生成类的过程中非常高效

CGLIB代理

1. 通过继承的方式动态生成目标类的代理

2. 通过修改字节码的方式来实现代理,可以在运行时动态的生成某个类的子类

3. 如果某个类使用final修饰,那么无法使用CGLIB做动态代理

4. CGLIB代理的核心是Enhancer类

使用ASM框架实现. ASM框架是一种可以操作字节码的框架

ASM在类生成之后的执行过程中非常高效

Spring AOP的代理选择


  • AOP类型的选择:

  • AspectJ​框架
  • Spring AOP​框架
  • 两种​AOP​类型分为基于​XML​配置文件的风格和基于 ​@AspectJ​注解的风格
  • AspectJ和Spring AOP比较:

  • AspectJ:

  • AspectJ​在功能完善度方法更具有优势
  • AspectJ​使用静态织入的方式实现​AOP
  • 依赖于特定的编译器​ajc

  • Spring AOP:

  • Spring AOP​中并没有提供完整的​AOP​功能,更加注重的是和​IOC​容器的结合来解决横切业务问题
  • Spring AOP​使用动态代理构建内部机制的动态织入的方式实现​AOP
  • Spring AOP​只是使用了和​AspectJ​相同的注解,但是底层是通过动态代理技术实现​AOP
  • 不依赖于​AspectJ​特定的编译器​ajc


  • 基于XML配置文件的风格个基于@AspectJ注解的风格比较:

  • 基于XML配置文件的风格:

  • aop:config

  • proxy-target-class :​ 是否作为代理的目标类,默认为​false
  • expose-proxy :​ 是否暴露代理的​Bean.​ 如果暴露,就可以通过​Spring AopContext​获取到代理的​Bean.​ 默认为不暴露

  • aop:pointcut

  • pointcut​的解析是生成一个​BeanDefinition,​ 并将配置的​id,expression​等属性保存到​BeanDefinition​中
  • BeanDefinition​的​ID​来自配置的id属性,如果没有配置就自动生成​ID
  • BeanDefinition​的​class​就是​AspectJExpressionPointcut
  • BeanDefinition​的​scope​为​prototype

  • aop:advisor

  • advice-ref :​ 必须的属性.这里的​advice​必须实现​org.aopalliance.aopAdvice​的子接口
  • pointcut-ref :​ 构建一个​RuntimeBeanReference​对象指向员​pointcut​的引用

  • aop:aspect
  • ref:​ 必须的属性. 用来指定​AOP​中的标签是哪一个​bean,​ 类和对象的方法
  • aop:declare-parents
  • 优点:
  • 基于​XML​配置文件由​POJO​支持,可以从配置文件中清楚地看出系统存在哪些方面​Aspect
  • 缺点:

  • 基于​XML​配置文件没有完全封装在一个地方,需求点​Joinpoint​分为支持​Bean​类的声明和配置文件中的​XML
  • 基于​XML​配置文件只支持单例的实例化切入点​Pointcut​模型,不能组合​XML​中声明命名的切入点


  • 基于@AspectJ注解的风格:

  • 基于 ​@AspectJ​的注解支持额外的实例化模型和丰富的切入点组合
  • 基于 ​@AspectJ​的注解可以将所有信息封装在一个模块​Aspect​中,将​Aspect​保持为模块化单元的优点
  • 基于 ​@AspectJ​的注解可以很方便地迁移到​AspectJ​框架中



  • Spring AOP中代理的选择:
  • Spring AOP​中的代理机制没有默认使用的代理 : (SpringBoot中默认开启了proxyTargetClass,默认都是使用CGLIB代理)

  • 如果代理的是实现接口的类,则使用​JDK​动态代理. 只要代理的类实现了至少一个接口,那么目标类型实现的接口都将会使用​JDK​动态代理
  • 如果代理的是子类,没有实现任何接口,则使用​CGLIB​代理

  • 也可以对实现接口的类强制使用​CGLIB​代理,需要满足以下条件:

  • 不能对​final​修饰的方法添加通知​Advice,​ 因为​final​修饰的方法无法被覆盖
  • CGLIB​代理中为了获取对目标类的引用,代理类必须要继承目标类,并且代理类会覆写所有​public​和​protected​方法,在内部将调用委托给目标类
  • Spring 3.2​之后不需要将​CGLIB​添加到项目类路径中,因为​CGLIB​已经包含在​jar​包​spring-core​中
  • Spring 4.0​之后,因为​CGLIB​代理实例通过​Objenesis​创建,所以代理对象的构造函数不会被调用两次 ​,CGLIB​代理类不会初始化构造代理类自身继承的任何成员变量.想要访问只能通过​getter​和​setter​方法. 只有当​JVM​不允许时,才会有​SpringAOP​支持的双重调用

  • 使用​CGLIB​代理时,需要将 ​<aop:config />​ 的​proxy-target-class​属性设置为​true
  • 如果使用 ​@AspectJ​自动代理时需要强制使用​CGLIB,​ 需要将 ​<aop:aspectj-autoproxy />​ 的​proxy-target-class​属性设置为​true



Spring AOP的实现模式


  • 代理模式:​ 接口 + 真正实现类 + 代理类

  • 真正实现类和代理类都需要实现接口
  • 实例化时使用代理类进行实例化
  • Spring AOP​的作用就是生成一个代理类来替换真正的实现类来对外提供服务

  • Spring中代理的实现模式:

  • Spring AOP​中使用 ​@EnableAspectJAutoProxy​注解,将​BeanPostProcessor​的子类​AnnotationAwareAspectJAutoProxyCreator.class​注入到容器中,然后在​Bean​生命周期中的后置处理器里判断切面的情况进行生成代理增强器,并且利用动态代理机制生成代理类
  • 真正实现类​的逻辑包含在​getBean()​ 方法中
  • getBean()​ 方法返回一个​Proxy​代理类实例
  • Proxy​代理类实例时​Spring​通过​JDK​动态代理或者​CGLIB​代理动态生成的

  • 因为​Spring AOP​中要通过​getBean()​ 方法查找和实例化容器中的​Bean,​ 所以​Spring AOP​只能作用于​Spring​容器中的​Bean,​ 无法作用于不是使用​Spring IOC​容器管理的对象
  • 总结:

  • Spring AOP​的核心是代理创建器​AbstractAutoProxyCreator​的子类,本质上是一个​Bean​的后置处理器
  • Spring​根据配置将相应的代理创建器注册到​Spring​容器中.如果项目中配置 ​@EnableAspectJAutoProxy​注解 ​,Spring​就会将​AnnotationAwareAspectJAutoProxyCreator​注册到​Spring​容器中
  • 因为代理创建器是一个​Bean​的后置处理器,所以会在​Bean​的初始化阶段被调用
  • 代理创建器会判断当前的​Bean​是否需要被代理,如果不需要代理就直接将原​Bean​实例返回.如果需要代理就使用动态代理技术根据当前​Bean​作为目标类创建一个代理类,并且将横切代码注入到代理类中,然后生成一个代理类的实例并返回,使用这个实例作为​Bean​的实例
  • 如果这个​Bean​是单例的,那么这个代理对象就会放置到​Spring​容器的单例池中,这样使用​getBean()​ 时,就可以直接从​Spring​容器中直接获取这个代理对象


AOP源码分析

Java架构师Day02-源码分析之Spring5_spring_09

  • Spring AOP​的配置方式包括 ​: XML​配置和注解配置

自定义AOP框架

Spring Cache框架源码分析

IOC

容器基本实现和组成

IOC容器设计原理及高级特性

IOC的注入原理

装配Bean方式

BeanFactory源码分析

BeanFactory与ApplicationContext的区别

FactoryBean与BeanFactory的区别

BeanDefinition与源码分析

IOC依赖实现

IOC中的循环依赖

  • 循环依赖:​ 两个类相互依赖,类似线程死锁的问题. 当创建一个对象需要依赖另一个对象,同时另一个对象也依赖这个对象,就会出现无法确定先创建哪个对象的问题

Spring中循环依赖解决


  • Spring Bean​中的几种依赖注入方式:

  • 构造函数注入
  • 属性注入
  • 通过方法注入.​ 可以是​setter​方法,也可以在方法上添加 ​@Autowired​注解

  • Spring​的作用域:

  • singleton
  • prototype
  • request
  • session
  • 非单例模式下发生循环依赖的问题都会直接抛出异常


Bean作用域

Bean生命周期

Spring IOC源码剖析

Spring IOC高级特性

Spring IOC高级应用

自定义IOC框架

Transaction

Spring声明式事务应用

声明式事务底层原理

Spring事务处理机制

事务的传播与监控

基于SpringJDBC手写ORM框架

MVC

MVC结构和原理介绍

Spring MVC的使用与流程解析

SpringMVC组成

Spring MVC九大组件剖析

MVC与IOC容器整合原理

HandlerMapping实现原理

HandlerAdapter实现原理

ViewResolver实现原理

Controller调用原理

动态参数匹配原理

Spring MVC源码剖析

Spring MVC设计模式

Spring MVC高级技术

Spring MVC高级实战

Spring MVC工作流

Spring MVC整合原理

Spring MVC乱码问题

SpringMVC与Structs2对比分析

手写实现SpringMVC框架

SSM整合策略

Spring5新特性

Spring5基本概念

Spring5.x的兼容性

Spring5的设计思想

Spring5体系结构

Spring5官方文档阅读技巧

Spring5环境搭建

Spring5的核心组件

通过常用的Spring拓展接口实现特殊需求

分析自带通用日志框架

多序列化数据格式绑定API

函数式风格的ApplicationContext

Kotlin表达式的支持

WebFlux模块

WebFlux和Servlet的区别

Testing改进

响应式编程

响应式编程基本概念

响应式编程特点

响应式流规范

响应式流中的异步和并行

Spring中的响应式编程

Project Reactor

Spring WebFlux高级实战

WebFlux核心响应式服务器

Spring WebFlux源码分析

Spring WebFlux和Spring MVC比较

WebFlux应用

响应式SpringBoot

响应式Spring Core

响应式Web

响应式SpringData

响应式Spring Session

响应式SpringSecurity

响应式SpringCloud

响应式Spring Test

响应式监控

响应式数据库访问

响应式程序测试

SpringData

SpringData支持的存储类型

SpringData接口规范与继承体系

SpringData方法定义规范

SpringData自定义Repository方法

SpringData JPA源码剖析

SpringData操作流程

SpringSecurity

SpringSecurity应用场景

SpringSecurity认证基本原理

SpringSecurity过滤器链

SpringSecurity认证流程剖析

SpringSecurity认证实战项目

SpringSecurity自定义认证策略

Session管理

CSRF防护机制

跨域与CORS

SpringSecurity授权流程分析

SpringSecurity授权实战

SpringSecurity权限表达式

SpringSecurity源码分析

RBAC权限模型