目录
Spring家族
Spring Core、Spring Security、Spring Data
Spring Core、Spring Security、Spring Data把单体应用开发好,不仅提供数据库访问、Web、MVC等功能,而且通过IOC、AOP让程序做到低耦合、可扩展。
Spring Core利用工厂模式依赖注入,代理模式AOP用来解耦应用组件。Spring MVC用来做Web应用的开发。后来因为开发SSM整合都是千篇一律的,所以开发出了懒人整合包starter即SpringBoot
Spring Boot
不仅加速开发效率,而且让程序从可用变成好用
IoC:控制反转
关于这部分知乎讲的比较好的链接
知乎链接2
依赖注入举例:
以下引用自https://www.zhihu.com/question/23277575/answer/169698662
IoC应用
- 读取应用程序提供的Bean配置信息,并在Spring容器中生成一份Bean注册表。
- 根据生成的Bean注册表通过反射机制实例化Bean,并装配好Bean之间的依赖关系。
- 将生成的Bean实例对象放入Spring容器中。
上图的这个方法主要是将BeanDefinition注册到BeanFactory接口的实现类
的beanDefinitionMap里,其中以BeanName为key,beanDefinition为value存储到beanDefinitionMap里,同时还将beanName存储到beanDefinitionNames里,以便后续bean的实例化。
BeanFactory:Spring框架最核心的接口
1、提供IOC的配置机制
2、包含Bean的各种定义,便于实例化Bean
3、建立Bean之间的依赖
4、Bean生命周期的控制
1、ListableBeanFactory:定义了访问容器中bean基本信息的若干方法,如查看bean的个数、获取某一类型bean的配置名、查看容器中是否包含某一bean等方法。
2、HierarchicalBeanFactory:父子级联的IoC容器接口,子容器可以通过接口方法访问父容器,但是父容器不能访问子容器。如Spring MVC中,展现层的bean位于子容器中,而业务层和持久层的bean位于父容器中。
3、ConfigurableBeanFactory:增强了IoC容器的可定制性。定义了设置类装载器、属性编辑器以及属性初始化后置处理器等方法。
4、AutowireCapableBeanFactory:将容器中的bean按某种规则,比如按名字/类型匹配,按这些规则对bean自动装配。
5、SingletonBeanRegistry:允许在运行期间向容器注册singletonBean实例的方法。
通过这些接口,证明了BeanFactory体系确实是提供了IoC的基础即依赖注入和bean的装载等功能。
上图展示BeanFactory可以按类型或者按名称来获取bean
isSingleton方法判断某个bean是否为单例。(spring中bean默认单例)
isPrototype方法则相反,其如果为true,那么调用getBean时会返回一个新的bean。
ApplicationContext:(BeanFactory的子接口之一)
Bean如何装载到IoC容器中:
注册Bean的两种方式:
1、使用configuration注解,手动new对象并标记为Bean
2、使用component和component scan注解,添加value自动扫描类信息并注册为Bean
第一种手动注册方式
@Configuration:将生成的实例注入到容器中
@Bean:将initPerson()方法返回的实例装配到IoC容器当中,name属性用来定义bean的名称,如果没定义,则名称默认为该方法名initPersion。
run()方法返回
第二种Spring Boot自动注册
如何实现依赖注入
通过Autowired注解,根据属性的类型找到合适的bean注入到实例中。
(如果有多个符合条件的bean需要通过注解primary告诉spring要注入的是哪个)
@Autowired:根据属性的类型找到对应的bean进行注入。这里dog类是pet接口的实现,所以这里会把dog的实例注入到person中。如果接口有两个实现类,则需要指定哪个,否则会报错。可在某个优先的类如Dog下使用@Primary注解,使得优先注入dog的实例。
refresh源码解析
refresh方法:
1、为IOC容器以及Bean的生命周期管理提供条件。
2、刷新Spring上下文信息,定义Spring上下文加载流程。其中ConfigurationClassParser解析各种标签比如@Bean
this.prepareRefresh();
1.设置spring容器的启动时间
2.撤销关闭状态
3.开启活跃状态
4.初始化属性元信息initPropertySource()
5.验证环境中必须存在的属性
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
获取BeanFactory实例
this.prepareBeanFactory(beanFactory);
对BeanFactory进行相关的设置,为后续的使用做准备
1.设置ClassLoader用来加载Bean
2.设置表达式解析器等等
this.postProcessBeanFactory(beanFactory);
模板方法,让不同的spring容器自定义扩展自己的加载方法,方法体为空
this.invokeBeanFactoryPostProcessors(beanFactory);
(会跳转到ConfigurationClassParser.doProcessConfigurationClass解析各种标签比如@Bean等)
调用工厂后处理器处理解析各类Bean标签(@Configuration/@Import/@Bean/@SpringbootApplication),扫描Bean文件,并解析成一个个的Bean,这里的Bean只是被加载到spring容器当中,由于spring容器的懒加载,这些Bean仅仅只是加载到容器,并没有连接和初始化,当程序需要使用到该Bean的时候,才会将bean连接和初始化。
this.registerBeanPostProcessors(beanFactory);
在容器中找出实现BeanPostProcessors接口的bean,设置到BeanFactory的属性之中,最后bean被实例化的时候会调用BeanPostProcessors(bean的后置处理器),
this.initMessageSource();
加载国际化信息
this.initApplicationEventMulticaster();
初始化事件的广播器,用于事件的发布
this.onRefresh();
模板方法:让不同的spring容器自定义扩展自己的加载方法,方法体为空
this.registerListeners();
注册监听器
this.finishBeanFactoryInitialization(beanFactory);
实例化BeanFactory中已经被注册但是没有实例化的所有bean(懒加载不需要被实例化)
this.finishRefresh();
初始化生命周期处理器等相关的事情
getBean方法的源码解析
通过AbstractBeanFactory实现的,其中getBean()方法又通过调用doGetBean()方法实例化bean。
Bean的创建过程;
1、实例化bean对象
2、如果通过aware接口声明了依赖关系,则会注入bean对基础设施层面的依赖
3、BeanPost前置处理:对实例化后的bean添加自定义逻辑
4、如果定义了after properties set方法:属性自定义
5、调用bean自定义的init方法
6、BeanPost后置处理:自定义方法
Bean销毁过程:
1、若实现DisposableBean接口,调用destroy方法
2、若配置destry-method属性,调用其配置的销毁方法
AOP
你了解SpringAop么
软件工程有一个基本原则,叫做关注点分离:就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题
面向切面变成AOP正是此种技术的体现,一种关注点分离的技术,我们的代码就是实现某种特定的业务逻辑,但是我们往往不能专注于业务逻辑,比如我们写业务逻辑的代码的同时,还要写事务管理、缓存、日志等等通用化的功能,而且每个通用的功能都要和这些业务混在一起
通用化功能代码的实现,对应的就是所谓的切面(Aspect)
业务功能代码和切面代码分开后,架构将变得高内聚低耦合
确保功能的完整性:切面最终需要被合并到业务中(Weave)
Aop的三种织入方式
编译时织入:需要特殊的Java编辑器,如AspectJ(在代码编译时,把切面代码融合进来,生成完整功能的Java字节码)
类加载时织入:需要特殊的Java类加载器,如AspectJ和AspectWerkz(在Java字节码加载的时候,把切面的字节码融合进来)
运行时织入:Spring采用的方式,通过动态代理的方式,实现简单(在运行时,通过动态代理的方式,调用切面代码,增加业务功能,动态代理会有性能上的开销,但好处是不需要特殊的编译器和类加载器)
AOP主要名词概念
Aspect通用功能的代码实现(RequestLogAspect)
Target被植入Aspect的对象(HelloController就是Target)
JoinPoint可以作为切入点的机会,所有方法都可以作为切入点(如前面的hello方法和hi方法)
PointCut:Aspect实际被应用在的JoinPoint,支持正则(定义通知应该切入到什么地方,Spring支持的切入点就是方法调用)
Advice类里的方法以及这个方法如何植入到目标方法的方式
Weaving:Aop的实现过程(切面应用到实际对象,从而创建新的代理对象的过程,对于Spring是初始化context中的对象时完成织入)
Advice的种类
前置通知(Before)
后置通知(AfterReturning)
异常通知(AfterThrowing)
最终通知(After)
环绕通知(Around)
AOP原理
AOP的实现:JdkProxy和Cglib
由AopProxyFactory根据AdvisedSupport对象的配置来决定
默认策略如果是接口,则用JdkProxy来实现,否则用后者
JdkProxy的核心:InvocationHandler接口和Proxy类
Cglib:以继承的方式动态生成目标类的代理
JdkProxy:通过Java内部的反射机制来实现
Cglib:借助ASM实现(一种能够操作字节码的框架)
反射机制在生成类的过程中比较高效
ASM在生成类之后的执行过程中比较高效(可以通过将ASM生成的类进行缓存,解决ASM生成类比低效的问题)
关于动态代理
以下来自知乎https://www.zhihu.com/search?type=content&q=cglib
代理模式:接口+真实实现类+代理类