lagou 爪哇 1-2 spring 笔记

2022-05-17 16:30:15 浏览数 (1)

任务一 自定义IoC&AOP框架

1.1 IoC

IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。

  1. 谁控制谁 (由 Spring IoC 容器来负责对象的生命周期和对象之间的关系)
  2. 控制什么 (bean对象创建,属性注入)
  3. 为何是反转 (依赖的对象由原来的主动获取变成被动接受,所以是反转)
  4. 哪些方面反转了(所依赖对象的获取被反转了)

hibernate中的inverse也是一种IoC

注入形式

  1. 构造器注入
  2. setter注入
  3. 接口注入

1.2 AOP

面向切面

使用场景:事务,日志,调用链追踪,性能分析

1.3 自定义步骤

  1. 统一资源读取
  2. bean对象工厂
  3. bean对象容器
  4. bean属性注入 (循环依赖,三级缓存,创建顺序问题,占位符,二级缓存)
  5. 动态代理实现AOP

jdk动态代理和cglib区别:

  • JDK 动态代理 JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是 InvocationHandler 接口和 Proxy 类。
  • CGLIB 动态代理 如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。当然,Spring 也支持配置,强制使用 CGLIB 动态代理。 CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。

任务二 Spring IoC高级应用与源码剖析

2.1 BeanFactory和ApplicationContext

ApplicationContext 接口扩展了 BeanFactory 接口,它在 BeanFactory 基础上提供了一些额外的功能。内置如下功能:

  • MessageSource :管理 message ,实现国际化等功能。
  • ApplicationEventPublisher :事件发布。
  • ResourcePatternResolver :多资源加载。
  • EnvironmentCapable :系统 Environment(profile Properties)相关。
  • Lifecycle :管理生命周期。
  • Closable :关闭,释放资源
  • InitializingBean:自定义初始化。
  • BeanNameAware:设置 beanName 的 Aware 接口。

BeanFactory

ApplicationContext

它使用懒加载

它使用即时加载

它使用语法显式提供资源对象

它自己创建和管理资源对象

不支持国际化

支持国际化

不支持基于依赖的注解

支持基于依赖的注解

BeanFactory 也被称为低级容器,而 ApplicationContext 被称为高级容器。

较常见的 ApplicationContext 实现方式:

  1. ClassPathXmlApplicationContext
    1. FileSystemXmlApplicationContext
    2. XmlWebApplicationContext

2.2 BeanPostProcessor

代码语言:javascript复制
public interface BeanPostProcessor {

    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

可以理解为一个hook,在bean初始化前后完成一些操作,比如rpc框架等在注册bean的前后可以自己完成一些初始化注册等

  1. BeanPostProcessor 的作用域是容器级别的,它只和所在的容器相关 ,当 BeanPostProcessor 完成注册后,它会应用于所有跟它在同一个容器内的 bean 。
  2. BeanFactory 和 ApplicationContext 对 BeanPostProcessor 的处理不同,ApplicationContext 会自动检测所有实现了 BeanPostProcessor 接口的 bean,并完成注册,但是使用 BeanFactory 容器时则需要手动调用 AbstractBeanFactory#addBeanPostProcessor(BeanPostProcessor beanPostProcessor) 方法来完成注册
  3. ApplicationContext 的 BeanPostProcessor 支持 Ordered,而 BeanFactory 的 BeanPostProcessor 是不支持的,原因在于ApplicationContext 会对 BeanPostProcessor 进行 Ordered 检测并完成排序,而 BeanFactory 中的 BeanPostProcessor 只跟注册的顺序有关。

2.3 Bean初始化流程

流程图

任务三 Spring AOP高级应用与源码剖析

3.1 aopalliance

Spring 对 AOP 联盟接口的变种。

  • Advice
    • Interceptor
      • MethodInterceptor
  • Joinpoint ,连接点接口。每个方法,都对应一个 Joinpoint 对象。
    • Invocation ,调用接口。
      • MethodInvocation ,方法调用接口。
        • ProxyMethodInvocation ,代理方法调用接口。在根目录的包里。
          • ReflectiveMethodInvocation ,反射方法调用实现类。在framework包里。
          • CglibMethodInvocation ,基于 CGLIB 方法调用实现类。在 framework 包里。
  • Advice ,定义的横切逻辑。在如下几个时机,可以进行执行:
    • Before :在目标方便调用前执行通知。
    • After :在目标方法完成后执行通知。
    • After Returning : 在目标方法执行成功后,调用通知。
    • After Throwing :在目标方法抛出异常后,执行通知。
    • Around :在目标方法调用前后均可执行自定义逻。

3.2 aspectj

对应 org.springframework.aop.aspectj 包。

  • ReflectiveAspectJAdvisorFactory
  • BeanFactoryAspectJAdvisorsBuilder
    • #buildAspectJAdvisors() 方法,构建所有 @Aspect 注解类的增强方法对应的 Advisor 对象。
  • AnnotationAwareAspectJAutoProxyCreator
    • #findCandidateAdvisors() 方法,获得所有增强方法对应的 Advisor 对象。
  • InstantiationModelAwarePointcutAdvisorImpl
  • AbstractAspectJAdvice ,基于 AspectJ ,实现 Advice 接口的 Advice 抽象类。
    • 有如下几个子类:
      • AspectJAroundAdvice
      • AspectJMethodBeforeAdvice
      • AspectJAfterAdvice
      • AspectJAfterReturningAdvice
      • AspectJAfterThrowingAdvice
    • 通过 ReflectiveAspectJAdvisorFactory#getAdvice(...) 方法,构建 AbstractAspectJAdvice 对象。
    • 通过 #invokeAdviceMethodWithGivenArgs(Object[] args) 方法,执行增强 Advice 的方法。【重要

知识点总结

aop 技术 Spring发现涉及到接口那就使用JDK动态代理,如果不涉及接口就使用CGLIB动态代理

从 IOC 容器中获取FactoryBean对象时需要的符号是&

aop 代理对象生成在那一个环节

  • beanpostprocessor
  • postprocessorAfterInitialization

lagou-transfer 基础案例的sql

代码语言:javascript复制
create database bank;

use bank;

CREATE TABLE `account` (
  `name` varchar(20) NULL,
  `money` int DEFAULT NULL,
  `cardNo` varchar(30) NOT NULL
) ENGINE=InnoDB;

insert into `account` values('韩梅梅', 10000, '6029621011001');
insert into `account` values('李大雷', 5000, '6029621011000');

表结构

课堂练习

1)问题⼀:在上述案例实现中,service 层实现类在使⽤ dao 层对象时,直接在 TransferServiceImpl 中通过 AccountDao accountDao = new JdbcAccountDaoImpl() 获得了 dao层对象,然⽽⼀个 new 关键字却将 TransferServiceImpl 和 dao 层具体的⼀个实现类 JdbcAccountDaoImpl 耦合在了⼀起,如果说技术架构发⽣⼀些变动,dao 层的实现要使⽤其它技术,⽐如 Mybatis,思考切换起来的成本?每⼀个 new 的地⽅都需要修改源代码,重新编译,⾯向接⼝开发的意义将⼤打折扣?

2)问题⼆:service 层代码没有竟然还没有进⾏事务控制 ?!如果转账过程中出现异常,将可能导致 数据库数据错乱,后果可能会很严重,尤其在⾦融业务。

参考

https://gitee.com/uza/lagou-java-camp/tree/master/第一阶段

0 人点赞