0%

spring

Spring

Spring有哪些模块

  • core:core、beans、context、spel
  • aop:aop、aspects、instrument
  • web:web、webmvc、webflux、websocket、servlet、portlet
  • data:jdbc、orm、oxm、transactions
  • other:test、messaging、jms

Spring核心是什么

  • IOC(Inversion of Control,控制反转)
  • AOP(Aspect Oriented Programming,面向切面编程)

IOC有多种实现方式

  • DI(Dependency Inject,依赖注入)
  • DL(Dependency Lookup,依赖查找)

Spring常用的注解

IOC

Basic

Advanced

DI

Register

三种注册方式

  • 基于xml文件:ApplicationContext类 + applicationContext.xml
  • 基于java注解:@Component、@Controller、@Service、@Repository
  • 基于java配置类:@Configuration + @Bean、@Configuration + @Import
  • 使用ImportSelector进行注册
  • 使用ImportBeanDefinitionRegistrar进行注册
  • 使用FactoryBean进行注册

ps:@Configuration上有@Component,所以使用组件扫描(@ComponentScan)时会自动注册到容器
ps:@Configuration可以用来注册第三方的bean

Component
Configuration
Import

@Import支持导入的

  • Configuration类
  • ImportSelector:返回需要导入的类的全限定名的字符串数组
  • ImportBeanDefinitionRegistrar:利用提供的BeanDefinitionRegistry添加bean

ps:@Import还支持导入不同类作为bean

Scope
Primary
Priority
Ordering
  • @Order不能控制依赖注入的优先级,但是@Order可以控制注入到List里的多个bean的顺序
  • @Order可以控制多个AOP的顺序
  • @Order可以控制多个CommandLineRunner的顺序

ps:@Primary和@Priority可以控制依赖注入的优先级

Inject

三种注入方式
  • field注入:字段注入(不推荐)
  • setter注入:setter注入
  • constructor注入:构造器注入
field注入的问题
  • 破坏对象的隐私和封装特性
  • 可能会导致循环依赖(Spring不能解决非单例bean的循环依赖)
  • 无法对static变量进行注入(因为static变量属于类不属于对象)
  • 无法对final变量进行注入(因为final变量只能在声明或者构造的时候赋值)
  • 手动创建的对象的依赖不会注入,使用时会导致空指针错误
setter注入的问题
  • 手动创建的对象的依赖不会注入,使用时会导致空指针错误

AutoWire

@Autowired的装配查找逻辑如下

  • 先按照byType的方式进行匹配
  • 如果匹配了多个,则又按照byName的方式进行匹配
  • 如果没匹配到,则抛出异常

@Resource的装配查找逻辑如下

  • 如果同时指定了name和type,name和type必须同时匹配
  • 如果只指定了name,只会按照byName的方式进行匹配
  • 如果只指定了type,只会按照byType的方式进行匹配
  • 否则先按照byName的方式进行匹配,找不到时再按byType的方式进行匹配
  • 如果匹配了多个或者没匹配到,则抛出异常

ps:byName的方式不会找到多个,因为name(bean id)在容器中必须是唯一的

Naming

Lazy

懒加载实现的关键对象

  • ProxyFactory
  • TargetSource

ps:Lazy是通过代理实现的,调用方法时实际上调用的是代理对象的代理方法,代理方法会调用时会通过 targetSource.getTarget 触发 beanFactory.doResolveDependency 的调用来完成目标对象的创建和缓存

Dependency

循环依赖解决的关键对象

  • Map
  • ObjectFactory

ps:单例对象创建后会缓存在Map中

循环依赖和注入方式
  • 单例bean字段注入setter注入可以通过三级缓存解决循环依赖
  • 单例bean构造器注入不能解决循环依赖,因为会导致构造函数的循环调用
  • 非单例bean时任何注入方式都不能解决循环依赖,因为非单例bean不会进行缓存
循环依赖和解决办法
  • 构造器注入 可以改成 setter注入 或者 字段注入
  • 使用 @Lazy延迟加载
循环依赖和三级缓存
1
2
3
4
5
6
7
8
9
10
11
/** Cache of singleton objects: bean name --> bean instance */
// 单例对象的cache:一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

/** Cache of early singleton objects: bean name --> bean instance */
// 提前暴光的单例对象的Cache:二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** Cache of singleton factories: bean name --> ObjectFactory */
// 单例对象工厂的cache:三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
  • 第三级缓存:存放bean对象的创建工厂(ObjectFactory)
  • 第二级缓存:存放已代理过的bean对象(Object)
  • 第一级缓存:存放已初始化的bean对象(Object)

第二级缓存的作用

  • 提前生成代理对象并注入到依赖中

ps:当存在 循环依赖时 需要提前生成代理对象进行注入,而不是注入目标对象
ps:当存在 循环依赖时 会提前生成代理对象,否则则在 初始化完成后 生成代理对象

Bean

什么是Bean:Bean指的是那些被IoC容器所管理的对象

bean的作用域

  • singleton:单例模式,全局只有一个
  • prototype:原型模式,每次使用时都创建一个新的Bean实例
  • request:每个请求一个,Web应用中有效
  • session:每个会话一个,Web应用中有效
  • globalsession:类似session,只有对portlet才有意义

ps:requestScope的bean是基于ThreadLocal实现的
ps:sessionScope的bean是基于sessionId和Map实现的

bean的线程安全

bean不是线程安全的

bean的生命周期

Spring钩子对象

  • XXXAware
  • XXXCapable
  • BeanPostProcessor
  • BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor
  • InitializingBean
  • DisposableBean
  • ImportSelector
  • ImportBeanDefinitionRegistrar
  • FactoryBean
  • ApplicationListener
bean的生命周期概览
  1. bean实例化
  2. bean属性填充
  3. bean初始化
  4. bean使用
  5. bean销毁

ps:bean实例化后会放入到(三级)缓存中

bean的生命周期详述
  1. instantiateBean:bean实例化
  2. populateBean:bean属性填充
  • 调用BeanNameAware.setBeanName
  • 调用BeanFactoryAware.setBeanFactory
  • 调用ApplicationContextAware.setApplicationContext
  1. initializeBean:bean初始化
  • 调用BeanPostProcessor.postProcessBeforeInitialization
  • 调用@PostConstruct注解标注的方法
  • 调用InitializingBean.afterPropertiesSet
  • 调用bean的init-method
  • 调用BeanPostProcessor.postProcessAfterInitialization
  1. useBean:bean使用
  2. destoryBean:bean销毁
  • 调用@PreDestroy注解标注的方法
  • 调用DisposableBean.destory
  • 调用bean的destory-method

ps:bean实例化后会放入到(三级)缓存中

Factory

  • IOC容器的接口类
    • BeanFactory
    • BeanDefinition
  • IOC容器的实现类
    • AnnotationConfigApplicationContext
    • ClassPathXmlApplicationContext
    • FileSystemXmlApplicationContext

ps:实现类分为独立版和web版

IOC容器的初始化流程

IOC容器的初始化概览
  • 将bean的配置信息解析成BeanDefinition并放到BeanDefinitionMap中
  • 根据BeanDefinition创建bean对象并进行依赖注入
IOC容器的初始化详述
  • prepareRefresh:context刷新前的预处理
  • obtainFreshBeanFactory:加载BeanFactory(默认实现是DefaultListableBeanFactory)
  • refreshBeanFactory:刷新BeanFactory
  • prepareBeanFactory:BeanFactory的预处理工作
  • postProcessBeanFactory:BeanFactory的后处理工作
  • invokeBeanFactoryPostProcessors:实例化实现了BeanFactoryPostProcessor接口的Bean并调用接口方法
  • registerBeanPostProcessors:注册BeanPostProcessor(Bean的后置处理器,在创建Bean的前后等执行)
  • initMessageSource:初始化MessageSource组件(做国际化功能:消息绑定,消息解析)
  • initApplicationEventMulticaster:初始化事件派发器
  • onRefresh:context的刷新回调,子类可以重写这个方法在容器刷新的时候可以自定义逻辑
  • registerListeners:注册应用的监听器,就是注册实现了ApplicationListener接口的监听器Bean
  • finishBeanFactoryInitialization:初始化所有的剩下的非懒加载的单例bean,并填充属性
  • finishRefresh:完成context的刷新

BeanFactory和FactoryBean的区别

  • BeanFactory:IOC容器的底层接口
  • FactoryBean:一种特殊的bean,getBean时会返回FactoryBean持有的bean

ps:Spring默认使用反射机制来创建Bean,可以使用FactoryBean来自定义创建过程
ps:getBean时如果需要返回FactoryBean本身,id前面需要添加 & 符号

BeanFactory和ApplicationContext的区别

  • BeanFactory:IOC容器的底层接口
  • ApplicationContext:IOC容器的高级接口,是BeanFactory的子接口,支持更多的功能

AOP

Basic

Advanced

Concept

AOP的核心概念

  • JoinPoint(连接点):任何可以切入的地方(比如java对象中的字段和方法)
  • Pointcut(切点):实际需要切入的地方的匹配规则
  • Advice(通知):切入后要做的事情
  • Aspect(切面):切点和通知的组合
  • Target(目标):被代理的对象
  • Proxy(代理):代理后的对象
  • Weaving(织入):将通知添加到切点上的实现过程
  • Introduction(引入):特殊的通知(可以为目标添加一些额外的属性和方法)

Ordering

AOP的通知顺序(Spring5)

  1. @AroundBefore
  2. @Before
  3. doSomething
  4. @AfterReturning | @AfterThrowing
  5. @After
  6. @AroundAfter

Scene

AOP的使用场景

  • 认证鉴权
  • 日志记录
  • 耗时统计
  • 异常处理
  • 重试管理
  • 事务管理
  • 异步管理
  • 缓存管理

Example

  • 事务管理:@Transactional
  • 异步管理:@Async

Invalid

AOP的失效场景

  • 代理的方法被同类的方法调用
  • 代理的方法不能被外部访问(private方法、protected方法)
  • 代理的方法不能被重写(final方法、static方法)
  • 代理的类不能被继承(final类)
  • 代理的类没有被Spring管理
  • 代理的对象是用户手动创建的

ps:JDK动态代理和CGLIB动态代理不能够代理 不能继承的类不能重写的方法 ,因为是通过生成子类并重写方法来实现的
ps:JDK动态代理和CGLIB动态代理不支持代理private方法,但AspectJ静态代理支持代理private方法
ps:JDK动态代理和CGLIB动态代理支持代理protected方法,但SpringAOP只会拦截public方法(因为AopUtils.canApply方法中使用的Class.getMethods只能获取public方法)

AOP同类方法调用时失效的原因分析

因为同类方法调用时方法A调用B不是通过AOP代理对象调用的,而是通过java的this引用调用的

AOP同类方法调用时失效的解决方案

  • 通过AopContext.currentProxy代替this调用从而可以使用代理对象
  • 通过ApplicationContext.getBean代替this调用从而可以使用代理对象
  • 通过在A类中注入A类型的字段a并使用对象a代替this调用从而可以使用代理对象

ps:AopContext.currentProxy需要添加 @EnableAspectJAutoProxy(exposeProxy=true) 注解

Proxy

Basic

Advanced

Spring代理的实现方案

  • 静态代理:编译时生成代理类
    • AspectJ:可以代理所有类
  • 动态代理:运行时生成代理类
    • JDK动态代理:只能对基于接口的类进行代理,不能对没有基于接口的类进行代理
    • CGLIB动态代理:可以代理所有类

ps:当 没有实现接口 或者 optimize配置为true 或者 proxy-target-class配置为true 时会使用CGLIB动态代理,否则使用JDK动态代理

JDK动态代理和CGLIB动态代理对比

  • 代理对象
    • JDK动态代理:实现了接口的类
    • CGLIB动态代理:任何类
  • 实现技术
    • JDK动态代理:基于java的反射机制
    • CGLIB动态代理:基于ASM字节码操作框架
  • 实现方式
    • JDK动态代理:通过反射生成接口的实现类
    • CGLIB动态代理:通过继承生成目标类的子类

Spring代理的实现方式

  • 手动实现
    • ProxyCreatorSupport
      • ProxyFactory + TargetSource:非Spring环境使用
      • ProxyFactoryBean:Spring环境使用
      • AspectJProxyFactory:AspectJ使用
  • 自动实现
    • AbstractAutoProxyCreator
      • BeanNameAutoProxyCreator
      • AbstractAdvisorAutoProxyCreator

Spring代理的实现案例

Spring代理的控制参数

@Configuration的proxyBeanMethods:是否对生成bean的方法进行代理,默认为true
@EnableAspectJAutoProxy的proxyTargetClass:是否强制使用CGLIB进行代理,默认为false

ps:SpringBoot中的 spring.aop.proxy-target-class 配置为true(默认为true)时优先级比注解里的proxyTargetClass属性高
ps:事务和异步是通过AOP实现的,所以@EnableTransactionManagement和@EnableAsync也有proxyTargetClass属性,在SpringBoot中也受 spring.aop.proxy-target-class 配置控制

Spring代理的生成时机

  • 提前生成代理对象:存在循环依赖时,在实例化(instantiateBean)的时候生成
  • 非提前生成代理对象:不存在循环依赖时,在初始化(initializeBean)的时候生成

ps:代码入口为 AbstractAutowireCapableBeanFactory.doCreateBean

SpringBoot

SpringBoot新增主要特性

  • 起步依赖:简化了pom文件中依赖的配置(利用maven的依赖传递通过Starter引入相关的依赖)
  • 自动配置:简化了bean对象的声明和注入(基于Spring的Import机制实现)
  • 条件配置:@Condition

SpringBootApplication

@SpringBootApplication由以下三个注解组成

  • @SpringBootConfiguration:被@Configuration注解所标注,和@Configuration没区别
  • @EnableAutoConfiguration:自动和有条件的加载工程里面的依赖的组件和配置
  • @ComponentScan:加载自己工程里面的自己的组件和配置

ps:@Configuration是不会被@EnableAutoConfiguration和@ComponentScan重复加载,因为@EnableAutoConfiguration和@ComponentScan的加载范围不同

AutoConfiguration

  • @EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)自动和有条件的加载所有依赖包里的配置
  • AutoConfigurationImportSelector通过SpringFactoriesLoader.loadFactoryNames加载META-INF/spring.factories资源文件里面指定的配置类
  • SpringFactoriesLoader.loadFactoryNames通过ClassLoader.getResources获取classpath中META-INF/spring.factories资源文件

SpringBootStarter

  • 起步依赖:利用maven的依赖传递通过Starter引入相关的依赖
  • 自动配置:应用启动时会通过 @SpringBootApplication 里的 @EnableAutoConfiguration 自动和有条件的加载所有依赖包里的组件和配置

SpringBootRunner

SpringBootActuator

SpringBootAdmin

Configuration

Configuration(File)

Web

Spring

SpringBoot

Configuration(Import)

  • @Import:引入java配置类
  • @ImportResource:引入xml配置文件
  • @PropertySource:引入properties和xml配置文件

ps:@PropertySource引入yaml配置文件需要自己实现

Configuration(Order)

多个配置冲突的解决方案

  • 合并多个文件
    • 重复的话则使用最开始的配置项并忽略后面的配置项
    • 重复的话则后面的配置项覆盖前面的配置项
  • 使用单个文件
    • 使用最先找到的文件
    • 使用最后找到的文件

ps:xml配置文件和properties配置文件都支持多个文件
ps:xml配置文件配置冲突时的解决方案是使用最开始的配置项并忽略后面的配置项
ps:properties配置文件配置冲突时的解决方案是后面的配置项覆盖前面的配置项

Configuration(Usage)

  • @Value:注入单个配置
  • @ConfigurationProperties:注入多个配置
  • @PropertySource:指定配置文件来源

Configuration(Enable)

EnableXXX的作用:启用某项特性和引入(@Import)相关的配置类使得相关的注解生效

Configuration(Function)

Configuration(MVC)

  • WebMvcConfigurer:WebMvc配置接口(提供了接口)
  • WebMvcConfigurerAdapter:WebMvc配置抽象类(实现了少量的方法)
  • WebMvcConfigurationSupport:WebMvc配置默认实现类(实现了大量的方法)

ps:由于java8中的接口支持默认方法了,所以WebMvcConfigurerAdapter已经不需要了
ps:SpringBoot中不用显示添加@EnableWebMvc,WebMvcAutoConfiguration会实现相同的效果

Configuration(Aop)

ps:SpringBoot中不用显示添加@EnableAspectJAutoProxy,AopAutoConfiguration会实现相同的效果

Configuration(Transaction)

ps:SpringBoot中不用显示添加@EnableTransactionManagement,TransactionAutoConfiguration会实现相同的效果

Configuration(Async)

Configuration(Schedule)

Configuration(Retry)

Configuration(Cache)

Configuration(Profile)

Theory

Class

TODO:Spring原理
TODO:懒加载、循环依赖、动态代理

XXXFactory

  • BeanFactory:IOC容器
  • ProxyFactory + TargetSource:负责 代理对象 创建的工厂
  • ObjectFactory:负责 目标对象 创建的工厂

BeanFactory

1
public Object getBean(String name) throws BeansException;

ProxyFactory

1
2
3
public Object getProxy();
public void setTarget(Object target);
public void setTargetSource(TargetSource targetSource);

TargetSource

1
2
3
4
5
6
public interface TargetSource extends TargetClassAware {
Object getTarget() throws Exception;
Class<?> getTargetClass();
boolean isStatic();
void releaseTarget(Object target) throws Exception;
}

ObjectFactory

1
2
3
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}

XXXBean

  • FactoryBean:可以创建目标对象的特殊Bean
  • ProxyFactoryBean:可以创建代理对象的特殊Bean

FactoryBean

1
2
3
4
5
6
7
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}

Annotation

@AliasFor

Generic

ResolvableType

Other

Design

  • 单例模式
  • 原型模式
  • 工厂模式
  • 建造者模式
  • 代理模式
  • 适配模式
  • 模板模式
  • 策略模式
  • 观察者模式

TODO:Spring设计模式

StateMachine

Utils

只想买包辣条