Spring笔记
本文最后更新于:2022年6月11日 下午
Spring源码1-3
SpringMVC源码4
第1节
Spring概念和使用
注解方式管理Bean:
1、注解方式 创建对象IOC
导入依赖 aop
1 |
|
这几个注解互相混用其实也可以,但是不推荐
1 |
|
2、注解方式 依赖注入DI
@Autowired 根据属性数据类型自动装配
@Qualifier 根据属性名称注入依赖
@Resources 可以根据类型,也可以根据名称注入
@Value 注入普通数据类型(8+String)
1 |
|
3、完全使用注解
创建配置类,替代xml配置文件
1 |
|
JDK Proxy动态代理:面向接口
- 必须有接口和实现类
- 只能增强接口中定义的方法
- 只能读取接口中方法的上注解
- 在不修改原有代码的 或者没有办法修改原有代码的情况下 增强对象功能 使用代理对象 代替原来的对象去完成功能
进而达到拓展功能的目的- JDK Proxy 动态代理面向接口的动态代理 一定要有接口和实现类的存在 代理对象增强的是实现类 在实现接口的方法重写的方法
- 生成的代理对象只能转换成 接口的不能转换成 被代理类
- 代理对象只能增强接口中定义的方法 实现类中其他和接口无关的方法是无法增强的
- 代理对象只能读取到接口中方法上的注解 不能读取到实现类方法上的注解
1 |
|
CGLIB动态代理: 面向父类
- 面向父类,和接口没有直接关系
- 不仅可增强接口中定义的方法,还可以增强一个类其他的方法
- 可以读取父类中方法上的所有注解
AOP
AOP切面编程一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现 日志处理,权限控制,性能检测,事务控制等
AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理
AOP中的术语辨析
1 连接点 Joint point:
类里面那些可以被增强的方法,这些方法称之为连接点
表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point
2 切入点 Pointcut:
实际被增强的方法,称之为切入点,”execution(* com.zzflybird.dao..add(..))”
表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方
3 通知 Advice:
实际增强的逻辑部分称为通知 (增加的功能)
Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
通知类型: 1 前置通知 2 后置通知 3 环绕通知 4 异常通知 5 最终通知
4 目标对象 Target:被增强功能的对象(被代理的对象)
织入 Advice 的目标对象
5 切面Aspect: 表现为功能相关的一些advice方法放在一起声明成的一个Java类
Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
6 织入 Weaving:
创建代理对象并实现功能增强的声明并运行过程
将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程
AOP的实现:基于注解(熟练)
Spring原理笔记
Spring Bean的创建生命周期:
根据一个类最终得到一个Bean对象,中间经过的步骤。
UserService.class—>无参构造方法(推断构造方法)—》普通对象—》依赖注入(属性赋值)—》初始化前(@PostConstruct)—–》初始化(InitializingBean)—》初始化后(AOP)—》代理对象—-》Bean
推断构造方法:使用哪个构造方法,构造方法的参数去哪里拿
Bean的销毁的生命周期
推断构造方法:
如果一个类中只有一个有参构造方法,spring就用这个。
如果一个类中有多个有参构造方法,spring不知道用哪一个,就会去找无参构造方法,如果找不到无参构造方法,就会报错。
有参构造方法的参数是一个类A的对象a,spring会先从spring容器中通过类名A找对应类型的Bean,如果找到了1个bean,就用这个bean给构造方法;如果使用类名A找到多个bean,就再用参数名a找与其名称相同的bean,把名称相同的bean给构造方法。
1 |
|
AOP原理
UserService等价于UserDao,OrderService等价于EmpDao
Spring生成Bean的过程:UserService.class—>无参构造方法(推断构造方法)—》普通对象—》依赖注入(属性赋值)—》初始化前(@PostConstruct)—–》初始化(InitializingBean)—》初始化后(AOP)—》代理对象—-》Bean
UserServiceProxy类—->代理对象—->代理对象.target = 普通对象
代理对象.test()方法—>进入到代理类的test方法中,执行target.test()方法
1 |
|
而代理对象里面的orderService (empDao)对象是没有赋值的,是null的。
普通对象是进行了依赖注入的,它的属性是有值的。
Spring生成Bean的过程:UserService.class—>无参构造方法(推断构造方法)—》普通对象—》依赖注入(属性赋值)—》初始化前(@PostConstruct)—–》初始化(InitializingBean)—》初始化后(AOP)—》代理对象—-》Bean
在初始化后(AOP)这一步,判断UserService要不要进行AOP,根据UserService中的方法是否被切了来判断。那么如何判断UserService中的有没有方法被切了呢?
1、找出所有的切面Bean
2、遍历所有的切面Bean
3、对于每一个切面Bean,遍历其所有方法
4、如果 某切面Bean中方法beforeMethod()的注解表达式中的某个方法test() == UserService中的某个方法test(),就把方法beforeMethod()放入map中缓存下来。存下来的方法beforeMethod()后面在test()方法前执行的时候直接去map中找方法来执行。map<UserService.class, method list>
Spring 事务原理
1 |
|
2小时打卡,AOP原理,Spring中的Bean(代理对象)与普通对象的区别?
Spring中的Bean就是一个代理对象。
加不加注解@Configuration对事务的作用:
两个不同的dataSource对象,一个是JdbcTemplate中自己的,另一个是Spring事务管理器创建的dataSource对象,创建连接conn,并关闭conn的自动提交。
JdbcTemplate和Spring事务管理器中的dataSource要是同一个dataSource,事务才会有效。
加了事务注解的方法中,调用该方法的对象是普通对象还是代理对象,如果是代理对象那么事务注解就有用。
第2节
手写Spring
Spring生成Bean的过程:
UserService.class—>无参构造方法(推断构造方法)—》普通对象—》依赖注入(属性赋值)—》初始化前(@PostConstruct)—–》初始化(InitializingBean)—》初始化后(AOP)—》代理对象—-》Bean
创建ConfigAppcontext类
创建Config配置类
创建@配置注解
实现Appcontext的构造方法
扫描方法
实例化对象
BeanDefination
beanDefinationMap
singletonObjectsMap
实现依赖注入—-》
1 |
|
进行初始化—-》UserService类 实现 InitializingBean接口来进行初始化,先自己定义InitializingBean接口,在UserService类中重写InitializingBean接口的方法。
1 |
|
BeanPostProcessor(最重要的东西),用于实现 初始化前,初始化后
实现 初始化前,初始化后 的功能——-》创建BeanPostProcessor接口,然后定义2个抽象方法:
postProcessBeforeInitialization()
初始化前postProcessAfterInitialization()
初始化后
用自己创建的ZzflybirdBeanPostProcessor类实现BeanPostProcessor接口,并标注注解,设置为Bean,使得spring可以扫描到。
在spring扫描的过程中,将 实现了BeanPostProcessor接口的类 进行实例化,得到对象,并保存到beanPostProcessorList中。
方便在后面createBean()中,
在 【依赖注入】–》【初始化前】——–》【初始化】———–》【初始化后】中的初始化前和初始化后中调用beanPostProcessorList中的对象的两个重写的方法。
每一个Bean都会调用postProcessBeforeInitialization()和postProcessAfterInitialization()方法。
1 |
|
Spring中AOP的底层就是通过BeanPostProcessor接口的两个方法实现的,因为这两个方法传入bean,然后可以在bean调用方法前,进行一些操作,这就是AOP。
基于 BeanPostProcessor 这个机制,传入bean,再传出bean,可以对bean做很多事情。
Aware回调功能:
在bean中获取beanName;
创建BeanNameAware接口,setBeanName()方法;
1 |
|
让一个Bean类实现这个BeanNameAware接口,重写setBeanName方法,Spring底层会自动调用setBeanName方法,为属性赋值。
1 |
|
Aware回调功能是在【依赖注入】后,【初始化前】之前执行的。
如何实现:
- 判断bean对象是否实现了BeanNameAware接口,即
bean instanceof BeanNameAware
- 然后将bean强制类型转换为BeanNameAware
- 再调用
bean.setBeanName(beanName)
方法即可,就设置了beanName。 - 注意:
setBeanName(beanName)
方法的内容是要自己写的哦。
1 |
|
总结:过一遍ZzflybirdApplicationContext类的初始化过程,和getBean的过程;
着重理解BeanPostProcessor 机制的实现原理。
第3节
4h48m, 03-Spring之底层架构核心概念解析
课程内容
1、BeanDefinition以及 BeanDefinitionReader
2、BeanFactory与ApplicationContext
3、Spring中的类型转化组件
4、Spring中的比较器OrderComparator
5、BeanPostProcessor与 BeanFactoryPostProcessor
6、Spring中特殊的Bean之FactoryBean
7、ExcludeFilter和IncludeFilter
8、Spring中类元数据读取 器之MetadataReader
创建BeanDefinition的方法有两种:
声明式定义Bean;声明式有:@Component、@Bean、xml声明Bean。spring底层会为这些Bean自动创建BeanDefinition对象,然后去读取Bean的各种信息和属性放入BeanDefinition对象中。
编程式定义Bean;
1、Spring的底层要使用编程式的方法创建BeanDefinition对象。如下图方框中的代码,在源码中很多使用这种方式创建BeanDefinition的。
注册Bean的:
AnotatedBeanDefinitionReader,传Bean.class
XmlBeanDefinitionReader,传sping.xml
扫描器:
ClassPathBeanDefinitionScanner,传一个string扫描路径。
总结:
AnotatedBeanDefinitionReader是用来注册BeanDefinition的,得到的是AnotatedGenricBeanDefinition
ClassPathBeanDefinitionScanner是用来扫描BeanDefinition的,得到的是ScanedGenericBeanDefinition
这两个BeanDefinition都是一个抽象类AbstractGenericBeanDefinition的子类。
所以BeanDefinition整体看来是有一个,但是在底层是细分为2种不同的BeanDefinition的。
BeanFactory & AppcationContext
Sping中,BeanFactory是一个接口,AppcationContext也是一个接口
1 |
|
AppcationContext接口是继承了BeanFactory接口的,
什么意思呢?
AppcationContext就是一个BeanFactory,BeanFactory接口有的方法它都有。
例如: context.getBean()方法。
1 |
|
ApplicationContext
除了继承了BeanFactory接口,还继承了其他的接口,这些其他的接口是BeanFactory所没有的功能;
EnvironmentCapable:获取环境变量的功能
MessageSource:进行国际化的功能
ApplicationEventPublisher:事件发布器
ResourcePatternResolver:拥有直接解析某些资源的功能
DefaultListableBeanFactory是BeanFactory一个非常强大的实现类。
BeanFactory可以用来注册beanDefinition对象。
ApplicationContext的getBean()方法的底层是通过创建一个DefaultListableBeanFactory作为beanFactory来调用beanFactory的getBean()方法的。
DefaultListableBeanFactory涉及到的接口:
HierarchicalBeanFactory:这个接口可以获得子BeanFactory的父BeanFactory
ListableBeanFactory:Listable展示Bean的名字、数量、统计信息,得到某一个类型的Bean信息
事件发布器;
事件监听器;
类型转换器:
ComponentScan扫描可以排除,也可以包含;
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!