任务一 自定义IoC&AOP框架
1.1 IoC
IoC 全称为 Inversion of Control
,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection
),即依赖注入。
- 谁控制谁 (由 Spring IoC 容器来负责对象的生命周期和对象之间的关系)
- 控制什么 (bean对象创建,属性注入)
- 为何是反转 (依赖的对象由原来的主动获取变成被动接受,所以是反转)
- 哪些方面反转了(所依赖对象的获取被反转了)
hibernate中的inverse也是一种IoC
注入形式
- 构造器注入
- setter注入
- 接口注入
1.2 AOP
面向切面
使用场景:事务,日志,调用链追踪,性能分析
1.3 自定义步骤
- 统一资源读取
- bean对象工厂
- bean对象容器
- bean属性注入 (循环依赖,三级缓存,创建顺序问题,占位符,二级缓存)
- 动态代理实现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 实现方式:
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- 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的前后可以自己完成一些初始化注册等
- BeanPostProcessor 的作用域是容器级别的,它只和所在的容器相关 ,当 BeanPostProcessor 完成注册后,它会应用于所有跟它在同一个容器内的 bean 。
- BeanFactory 和 ApplicationContext 对 BeanPostProcessor 的处理不同,ApplicationContext 会自动检测所有实现了 BeanPostProcessor 接口的 bean,并完成注册,但是使用 BeanFactory 容器时则需要手动调用
AbstractBeanFactory#addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
方法来完成注册 - ApplicationContext 的 BeanPostProcessor 支持 Ordered,而 BeanFactory 的 BeanPostProcessor 是不支持的,原因在于ApplicationContext 会对 BeanPostProcessor 进行 Ordered 检测并完成排序,而 BeanFactory 中的 BeanPostProcessor 只跟注册的顺序有关。
2.3 Bean初始化流程
流程图
任务三 Spring AOP高级应用与源码剖析
3.1 aopalliance
Spring 对 AOP 联盟接口的变种。
- Advice
- Interceptor
- MethodInterceptor
- Interceptor
- Joinpoint ,连接点接口。每个方法,都对应一个 Joinpoint 对象。
- Invocation ,调用接口。
- MethodInvocation ,方法调用接口。
- ProxyMethodInvocation ,代理方法调用接口。在根目录的包里。
- ReflectiveMethodInvocation ,反射方法调用实现类。在framework包里。
- CglibMethodInvocation ,基于 CGLIB 方法调用实现类。在 framework 包里。
- ProxyMethodInvocation ,代理方法调用接口。在根目录的包里。
- MethodInvocation ,方法调用接口。
- Invocation ,调用接口。
- 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/第一阶段