Spring
Spring
织IOC
Xml 配置 Bean
结构
配置样例
1 | <bean id = "UserDao" |
配置解析
- 关键字
- Id 为 bean 对象 name,name 为别名,可有多个
- Ref 其他bean 对象
- Singleton ,Bean 对象只有一个储存在缓存中,仅在每个 Spring容器中有效,不全局有效
- Prototype,每次请求该 Bean 时返回一个 Bean 的新实例
- Lazy-init,延迟加载,Spring 容器创建时不会立即创建 bean 示例,等待用时再创建并加载到单例池中
- Init-method 与 Destroy-method,指定初始化方法与销毁方法
- Constructor-arg 构造参数, name 参数名称,value 参数值 ref 引用注入另一个 bean 对象
- ByType (自动装配 set 方法,依据类型,但不能多个相同 bean 类型) or byName (自动装配 set 方法,依据名称)
- Profiles 属性区分开发环境,区分不同的 beans
- Import 模块化,引入其他模块的配置 xml 文件
- Alias 取别名
- Parent 继承有配置的属性,在子Bean中必须也要存在,并且可以进行注入,否则会出现错误 当然,如果子类中某些属性比较特殊,也可以在继承的基础上单独配置
- Abstract 如果我们只是希望某一个Bean仅作为一个配置模版供其他Bean继承使用,那么我们可以将其配置为abstract,这样,容器就不会创建这个Bean的对象了:
- Bean 的注入方式
- Bean 的Set 方法
- Bean 的构造方法
- InitializingBean 接口
- 只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。Spring初始化bean的时候,如果该bean实现了InitializingBean接口,并且同时在配置文件中指定了init-method,系统则是先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。
- 静态工厂方法与实例工厂方法
- 静态工厂方法不需要先定义 factorybean
Bean 的 get 方法
1 | Object getBean(String beanName) |
Spring 配置非自定义的 Bean
Bean 的实例化基本流程
Bean 工厂的后处理器
流程
代码
1 | //github上 min-spring的实现过程,此时未使用applicationContext |
- BeanDefinitionRegistryPostProcessor 继承自上面的 BeanFactoryPostProcessor,说明 BeanDefinitionRegistryPostProcessor对 BeanFactoryPostProcessor提供的方法进行了增强扩展。一句话总结其功能作用就是注册beanDefinition的.
- ConfigurationClassPostProcessor 就是实现
BeanDefinitionRegistryPostProcessor
来完成配置类及其相关注解解析得到beanDefinition注册到Spring上下文中的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35//使用applicationContext
public class Boo {
private Long id;
private String name;
}
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注入boo
BeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.shepherd.common.bean.Boo");
registry.registerBeanDefinition("boo", beanDefinition);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor execute...");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("boo");
if (Objects.nonNull(beanDefinition)) {
beanDefinition.setDescription("hello,world");
}
}
}
public class MyConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
BeanDefinition beanDefinition = applicationContext.getBeanDefinition("boo");
System.out.println(beanDefinition.getDescription());
}
} - 上述实现需要配置 xml 文件
自定义注解
元注解
- Target、@Retention、@Inherited、@Documented 元注解的作用就是负责注解其他注解
- @Target:
描述注解的使用范围
- ElementType.TYPE 应用于类、接口(包括注解类型)、枚举
- ElementType.FIELD 应用于属性(包括枚举中的常量)
- ElementType.METHOD 应用于方法
- ElementType.PARAMETER 应用于方法的形参
- ElementType.CONSTRUCTOR 应用于构造函数
- ElementType.LOCAL_VARIABLE 应用于局部变量
- ElementType.ANNOTATION_TYPE 应用于注解类型
- ElementType.PACKAGE 应用于包
- @Retention:表明该注解的生命周期
- RetentionPolicy.SOURCE 编译时被丢弃,不包含在类文件中
- RetentionPolicy.CLASS JVM加载时被丢弃,包含在类文件中,默认值
- RetentionPolicy.RUNTIME 由JVM 加载,包含在类文件中,在运行时可以被获取到
- @Inherited:是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
- @Documented:表明该注解标记的元素可以被Javadoc 或类似的工具文档化
流程
代码
1 | // 注解的作用 类似代替原有的 |
Bean 后置处理器
流程
- BeanPostProcessor
- Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,BeanPostProcessor 就是这一阶段的对外扩展点,我们称之为Bean后置处理器。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。
代码
1 | //xml中配置MyBeanPostProcessor 不使用注解的流程 |
- 说明BeanPostProcessor方法的执行时间点和顺序,BeanPostProcessor是在bean实例化之后,对bean的初始化init()方法前后进行回调扩展的,这时候你可能会想如果要对bean的实例化前后进行扩展怎么办?Spring肯定也想到这一点,提供了继承自 BeanPostProcessor 的扩展类后置处理器
扩展
InstantiationAwareBeanPostProcessor该接口继承了BeanPostProcess接口
BeanPostProcess接口只在bean的初始化阶段进行扩展 InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段
该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段 和初始化阶段
postProcessBeforeInstantiation:实例化bean之前,相当于new这个bean之前
postProcessAfterInstantiation:实例化bean之后,相当于new这个bean之后
postProcessPropertyValues:bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现
postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后
SmartInstantiationAwareBeanPostProcessor该扩展接口集成自上面InstantiationAwareBeanPostProcessor,有3个触发点方法:
predictBeanType:该触发点发生在postProcessBeforeInstantiation之前这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。(不太常用)
determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。
getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。
Bean 的生命周期
完整生命周期
初始化阶段
属性填充
循环依赖
三级缓存
实例流程
Aware
概述
解释
Aware 接口是一个具有标识作用的超级接口,指示 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回调的方式。Aware 接口是一个空接口,具体的实现由各个子接口决定,且该接口通常只包含一个单个参数并且返回值为void的方法**。可以理解就是 set 方法。该方法的命名方式为 set + 去掉接口名中的 Aware 后缀,即 XxxAware 接口,则方法定义为 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。注意,仅实现Aware接口,不会提供任何默认功能,需要明确的指定实现哪个子接口。
通俗的来说,Aware 翻译过来的意思是有感知的,察觉的,如果类上实现了该接口,表明对什么有感知,比如 BeanNameAware, 表示知道了自己的Bean Name。
可以看看
注解配置
基本配置
基本配置代码
1 | //使用注解时xml文件中还必须有配置,让spring扫描注解来获得bean对象 |
基本注解衍生注解
依赖注入注解
- Autowired 依据类型进行注入,如果同一类型的 bean 有多个,会根据名字二次匹配
非自定义 bean 注解
Bean 配置类
1 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> </beans> |
其他配置类
- @Profile 切换环境
- @Primary 标注 bean 的优先级会更高,在通过类型获取 bean 或者通过@Autowired 根据类型进行注入时优先级会更高
Xml 与注解方式
AOP
AOP 概念
Xml 配置 AOP
流程
- 导入 AOP 相关坐标
- 准备目标类,增强类,并配置给 Spring 管理
- 配置切点表达式(哪些方法被增强)
- 配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)
代码
1 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" |
1 | public class example { |
配置解析
AOP 两种代理模式
- JDK
- 目标类有接口,是基于接口类生成实现类的代理对象
- 有接口,默认实现
- Cglib
- 目标类无接口且不能用final 修饰,是基于被代理对象动态生成子对象为代理对象
- 无接口,默认实现,但可强行使用