高级用法
1. 启动之后直接执行某一段代码
@Component //此类要交给spring管理
@Order(value=1) //首先执行
//@Order(value=2) //其次执行
public class ConsumerRunner implements ApplicationRunner{
@Oberride
public void run(ApplicationArgumers args) throws Exception{
//代码
System.out.println("需要在springBoot项目启动时执行的代码---");
}
}
2. 注入Application容器
两种方式:
- 实现ApplicationContextAware接口
- @Autowired ApplicationContext
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private LoggerWithMDC logger = LoggerWithMDC.getLogger(this.getClass(), "assets-event");
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
logger.info("setApplicationContext:{}", applicationContext);
}
}
两种最终结果相同,实现接口可以封装更多方法,如getBean,getBeansWithAnnotation等。
容器与bean
容器接口
BeanFactory
是ApplicationContext的父接口,是spring的核心容器。实际上的控制反转、依赖注入、Bean生命周期的各种功能都由它的实现类提供。
BeanFactory的主要实现类
ApplicationContext
是 BeanFactory 的子接口。它组合并扩展了 BeanFactory 的功能,不仅仅是继承关系,如:
-
国际化
语言支持:
applicationContext.getMessage()
-
通配符方式获取一组 Resource 资源
applicationContext.getResources("classpath*:META-INF/spring.factories")
-
整合 Environment 环境(能通过它获取各种来源的配置信息)
ConfigurableEnvironment environment = context.getEnvironment(); String java_home = environment.getProperty("java_home");
-
事件发布与监听,实现组件之间的解耦
//定义事件 public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } } //发送事件 context.publishEvent(new MyEvent(context)); //接受事件 @EventListener public void listen(MyEvent event) { System.out.println("接受事件" + event); }
容器实现
Spring 容器的实现
- DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现
- ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
- FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
- XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
- AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
- AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
- AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
- AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来
DefaultListableBeanFactory实现
是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现。
- beanFactory 可以通过 registerBeanDefinition 注册一个 bean definition 对象
- 平时使用的配置类、xml、组件扫描等方式都是生成 bean definition 对象注册到 beanFactory 当中
- bean definition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
- beanFactory 需要手动调用 beanFactory 后处理器对它做增强
- 例如通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition
- beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
- 例如 @Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
- bean 后处理的添加顺序会对解析结果有影响,如同时加 @Autowired,@Resource
- beanFactory 需要手动调用方法来初始化单例
- beanFactory 需要额外设置才能解析 ${} 与 #{}
常见 ApplicationContext 实现
- AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器
- AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器
Bean的生命周期
bean的装载过程:
xml(注解)->bean defination -> bean factory -> 实例化出bean。
BeanDefinitionReader
:从不同格式的定义bean信息中读取,完成从xml文件到bean defination的转变BeanDefinition
:其中保存了从配置文件中读取到的该bean的各种信息,以后所有的操作都是对这个对象的操作。Bean Definition从加载、解析、处理、注册到BeanFactory的过程,也就是IOC容器的初始化过程BeanFactory
:是Spring bean容器的根接口.提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。BeanFactory是一个接口,Spring为BeanFactory提供了多种实现ApplicationContext
:ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。ApplicationContext的主要实现类是ClassPathXmlApplicationContext
和FileSystemXmlApplicationContext
,前者默认从类路径加载配置文件,后者默认从文件系统中加载配置文件
Spring 管理bean的生命周期主要阶段(doGetBean):
-
处理名称,检查缓存,若缓存中存在可以直接返回
- 先把别名解析为实际名称,再进行后续操作
- singletonObjects:一级缓存,存放单例成品对象
- singletonFactories:三级缓存,放单例工厂
- earlySingletonObjects:二级缓存,放单例工厂的产品,成为提前单例对象
-
按照scope实例化Bean:Spring启动,查找并加载需要被Spring管理的bean,根据 bean 的构造方法或者工厂方法来创建 bean 实例对象
- singleton scope:从单例池中获取,如果没有就创建并放入单例池
- prototype scope:从不缓存bean,每次请求都创建新的
- request scope:从request对象范围内获取bean
-
依赖注入:实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。紧接着,Spring根据BeanDefinition中的信息进行依赖注入。根据 @Autowired,@Value 或其它一些手段,为 bean 的成员变量填充值、建立关系
-
初始化
-
注入Aware接口:检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean
-
BeanPostProcessor:经过上述几个步骤后,bean对象已经被正确构造,但如果想要对象被使用前再进行一些自定义的处理,就可以通过BeanPostProcessor接口实现。
-
postProcessBeforeInitialzation
-
postProcessAfterInitialzation
实现了此接口会将业务代码与框架耦合,spring建议使用@postconstruct
-
-
InitializingBean:此阶段无法修改对象本身,只能增加一些额外的逻辑。
-
init-method:init-method本质上仍然使用了InitializingBean接口。
四个初始化步骤的调用顺序:Aware接口–>@postconstruct–>InitializingBean接口–>指定init-method方法
-
-
判断并登记可销毁bean
- 实现了DisposableBean或AutoCloseable接口,则为可销毁bean
- 自定义了destroyMethod
- 有@PreDestroy标注的方法
singleton scope的可销毁bean存放于beanFactory的成员变量中
-
销毁:在容器关闭时,会销毁所有单例对象(即调用它们的销毁方法)
- prototype 对象也能够销毁,不过需要容器主动调用
同一bean中不同形式销毁方法的调用顺序:@PreDestroy–>DisposableBean接口销毁–>destroyMethod方法销毁
创建前后的增强
- postProcessBeforeInstantiation
- 这里返回的对象若不为 null 会替换掉原本的 bean,并且仅会走 postProcessAfterInitialization 流程
- postProcessAfterInstantiation
- 这里如果返回 false 会跳过依赖注入阶段
依赖注入前的增强
- postProcessProperties
- 如 @Autowired、@Value、@Resource
初始化前后的增强
- postProcessBeforeInitialization
- 这里返回的对象会替换掉原本的 bean
- 如 @PostConstruct、@ConfigurationProperties
- postProcessAfterInitialization
- 这里返回的对象会替换掉原本的 bean
- 如代理增强
销毁之前的增强
- postProcessBeforeDestruction
- 如 @PreDestroy
spring循环依赖解决:三级缓存(set方法进行依赖注入)
只有单例模式的bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean每次请求都会创建一个新的对象,所以非单例的bean不会放在缓存中。
- 三级缓存中存放的内容
- 一级缓存:成品对象–concurrenthashmap,每个bean在容器中只有一份即实现singleton
- 二级缓存:存放发生循环依赖时的半成品对象(可能是代理bean也可能是原始bean)–hashmap ,创造完成品对象删除
- 三级缓存:存放工厂对象,发生循环依赖时会由工厂获取 产品。lambda表达式,保证在容器的运行过程中同名的bean对象只有一个–hashmap
- 只有一级缓存无法解决:成品对象与半成品对象放在一起,会导致获取对象时获取到未初始化完成的对象
- 二级缓存可以解决循环依赖的问题,但是无法实现aop的功能,在进行aop时,会导致获取到非最终的bean
- 三级缓存作用:实现aop相关功能时需要创建代理对象,由于容器中只能存在单个实例,因此当一个对象需要被代理时就要使用代理对象对他进行覆盖,然而无法确定其时机。因此lambda完成了代理对象替换非代理对象的工作,确保返回的是唯一的对象。所有的bean对象在创建的时候都要优先放在三级缓存中,在后续的使用过程中,根据是否需要代理,返回对应的对象
三级缓存无法解决构造循环依赖,可以用@Lazy解决
Bean 后处理器
- @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能,这些扩展功能由 bean 后处理器来完成
- 不同后处理器负责增强不同功能
- AutowiredAnnotationBeanPostProcessor 解析 @Autowired 与 @Value
- CommonAnnotationBeanPostProcessor 解析 @Resource、@PostConstruct、@PreDestroy
- ConfigurationPropertiesBindingPostProcessor 解析 @ConfigurationProperties
- ContextAnnotationAutowireCandidateResolver 负责获取 @Value 的值,解析 @Qualifier、泛型、@Lazy 等
@Autowired bean 后处理器运行分析
- AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata 用来获取某个 bean 上加了 @Value @Autowired 的成员变量,方法参数的信息,表示为 InjectionMetadata
- InjectionMetadata 可以完成依赖注入
- InjectionMetadata 内部根据成员变量,方法参数封装为 DependencyDescriptor 类型
- 有了 DependencyDescriptor,就可以利用 beanFactory.doResolveDependency 方法进行基于类型的查找
BeanFactory 后处理器
- ConfigurationClassPostProcessor 可以解析
- @ComponentScan
- @Bean
- @Import
- @ImportResource
- MapperScannerConfigurer 可以解析
- Mapper 接口
这些扩展功能由不同的BeanFactory 后处理器来完成,完成了对核心容器的扩展。
- @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
- Mapper 接口被 Spring 管理的本质:实际是被作为 MapperFactoryBean 注册到容器中
- 这些扩展功能由不同的 BeanFactory 后处理器来完成,其实主要就是补充了一些 bean 定义
Aware 接口
- Aware 接口提供了一种【内置】 的注入手段,例如
- BeanNameAware 注入 bean 的名字
- BeanFactoryAware 注入 BeanFactory 容器
- ApplicationContextAware 注入 ApplicationContext 容器
- EmbeddedValueResolverAware 注入 ${} 解析器
- InitializingBean 接口提供了一种【内置】的初始化手段
- 对比
- 内置的注入和初始化不受扩展功能的影响,总会被执行
- 而扩展功能受某些情况影响可能会失效
- 因此 Spring 框架内部的类常用内置注入和初始化
配置类 @Autowired 失效分析
Java 配置类不包含 BeanFactoryPostProcessor 的情况
Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效
对应代码
@Configuration
public class MyConfig1 {
private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
log.debug("注入 ApplicationContext");
}
@PostConstruct
public void init() {
log.debug("初始化");
}
@Bean // ⬅️ 注释或添加 beanFactory 后处理器对应上方两种情况
public BeanFactoryPostProcessor processor1() {
return beanFactory -> {
log.debug("执行 processor1");
};
}
}
注意
解决方法:
- 用内置依赖注入和初始化取代扩展依赖注入和初始化
- 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
初始化和销毁顺序
Spring 提供了多种初始化手段,如果同一个 bean 用了声明了 3 个初始化方法,那么它们的执行顺序是
- @PostConstruct 标注的初始化方法
- InitializingBean 接口的初始化方法
- @Bean(initMethod) 指定的初始化方法
与初始化类似,Spring 也提供了多种销毁手段,执行顺序为
- @PreDestroy 标注的销毁方法
- DisposableBean 接口的销毁方法
- @Bean(destroyMethod) 指定的销毁方法
Scope
在当前版本的 Spring 和 Spring Boot 程序中,支持五种 Scope
- singleton,容器启动时创建(未设置延迟),容器关闭时销毁
- prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁
- request,每次请求用到此 bean 时创建,请求结束时销毁
- session,每个会话用到此 bean 时创建,会话结束时销毁
- application,web 容器用到此 bean 时创建,容器停止时销毁
对于单例对象来讲,依赖注入仅发生了一次,如果在 singleton 注入其它 scope 都会有问题,解决方法有
- @Lazy
- @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
- ObjectFactory
- ApplicationContext.getBean
AOP
AOP 底层实现方式之一是代理,由代理结合通知和目标,提供增强功能
除此以外,aspectj 提供了两种另外的 AOP 底层实现:
- 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中
- 第二种是通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能
简单比较的话:
- aspectj 在编译和加载时,修改目标字节码,性能较高
- aspectj 因为不用代理,能突破一些技术上的限制,例如对构造、对静态方法、对 final 也能增强
- 但 aspectj 侵入性较强,且需要学习新的 aspectj 特有语法,因此没有广泛流行
jdk 动态代理
使用jdk 动态代理
public class JdkProxyDemo {
interface Foo {
void foo();
}
static class Target implements Foo {
public void foo() {
System.out.println("target foo");
}
}
public static void main(String[] param) {
// 目标对象
Target target = new Target();
// 代理对象
Foo proxy = (Foo) Proxy.newProxyInstance(
Target.class.getClassLoader(), new Class[]{Foo.class},
(p, method, args) -> {
System.out.println("proxy before...");
Object result = method.invoke(target, args);
System.out.println("proxy after...");
return result;
});
// 调用代理
proxy.foo();
}
}
jdk 动态代理要求目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系
实现 jdk 动态代理
public class A12 {
interface Foo {
void foo();
int bar();
}
static class Target implements Foo {
public void foo() {
System.out.println("target foo");
}
public int bar() {
System.out.println("target bar");
return 100;
}
}
public static void main(String[] param) {
// ⬇️1. 创建代理,这时传入 InvocationHandler
Foo proxy = new $Proxy0(new InvocationHandler() {
// ⬇️5. 进入 InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
// ⬇️6. 功能增强
System.out.println("before...");
// ⬇️7. 反射调用目标方法
return method.invoke(new Target(), args);
}
});
// ⬇️2. 调用代理方法
proxy.foo();
proxy.bar();
}
}
//模拟代理实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// ⬇️这就是 jdk 代理类的源码, 秘密都在里面
public class $Proxy0 extends Proxy implements A12.Foo {
public $Proxy0(InvocationHandler h) {
super(h);
}
// ⬇️3. 进入代理方法
public void foo() {
try {
// ⬇️4. 回调 InvocationHandler
h.invoke(this, foo, new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public int bar() {
try {
Object result = h.invoke(this, bar, new Object[0]);
return (int) result;
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
static Method foo;
static Method bar;
static {
try {
foo = A12.Foo.class.getMethod("foo");
bar = A12.Foo.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
}
代理利用了多态、反射的知识
- 方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部
- 通过接口回调将【增强逻辑】置于代理类之外
- 配合接口方法反射(是多态调用),就可以再联动调用目标方法
- 限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现
cglib 代理
public class CglibProxyDemo {
static class Target {
public void foo() {
System.out.println("target foo");
}
}
public static void main(String[] param) {
// 目标对象
Target target = new Target();
// 代理对象
Target proxy = (Target) Enhancer.create(Target.class,
(MethodInterceptor) (p, method, args, methodProxy) -> {
System.out.println("proxy before...");
Object result = methodProxy.invoke(target, args);
// 另一种调用方法,不需要目标对象实例
// Object result = methodProxy.invokeSuper(p, args);
System.out.println("proxy after...");
return result;
});
// 调用代理
proxy.foo();
}
}
- cglib 不要求目标实现接口,它生成的代理类是目标的子类,因此代理与目标之间是子父关系
- 限制⛔:根据上述分析 final 类无法被 cglib 增强
jdk 和 cglib 在 Spring 中的统一
Spring 中对切点、通知、切面的抽象如下
- 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut
- 通知:典型接口为 MethodInterceptor 代表环绕通知
- 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut
代理相关类图
- AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现
- AopProxy 通过 getProxy 创建代理对象
- 图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)
- 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor
- ProxyFactory 用来创建代理
- 如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
- 如果没有指定接口,或者 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
- 例外:如果目标是接口类型或已经是 Jdk 代理,使用 JdkDynamicAopProxy
注意
- 要区分本章节提到的 MethodInterceptor,它与之前 cglib 中用的的 MethodInterceptor 是不同的接口
设计模式
模板方法设计模式
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
// 模板方法 Template Method Pattern
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化 " + bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor processor) {
processors.add(processor);
}
}
static interface BeanPostProcessor {
public void inject(Object bean); // 对依赖注入阶段的扩展
}
单例模式
单例bean借鉴了思想,严格意义上并不是单例模式。因为只保证了一个容器有一个唯一bean,但是系统可以有多个容器
建造者模式
链式调用,在build之前对象不可用
工厂模式
beanFactory,applicationContext
适配器模式
HandlerAdapter–控制器实现有多种
组合模式
将分散的调用组合起来,统一调用接口,它的特征是与具体工作的实现实现同一个接口,当调用组合对象的接口方法时,其实是委托具体干活的实现来完成
代理模式
装饰器模式
观察者模式
事件与监听者
模板方法
以Template Abstract命名的类
refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/* 完成context的初始化准备工作.
1. 创建和准备了Environment对象:
1. systemProperties Java虚拟机等提供的
2. systemEnvironment 操作系统提供的
3. 自定义Properties 自定义properties yml文件中提供的
2. 作用:如@value注入,使用的就是Environment对象中的值
*/
prepareRefresh();
//---------------------------------------------------------------------
/* 生成一个beanFactory供context使用,容器的核心功能都由beanFactory提供.
1. ApplicationContext扩展了beanFactory的功能,但是并没有重复实现beanFactory已有功能.
2. beanFactory的作用是负责bean的创建,依赖注入和初始化.其中包含
1. beanDefinationMap:作为bean的设计蓝图,规定了bean的特征,如依赖关系,单例多例,初始化销毁方法.
2. singletonObjects
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/* 完成context中的beanFactory初始化准备工作.
1. 对beanFactory的一些成员变量进行初始化赋值:
1. beanExpressionResolver spring内部类型转换器,如解析${}
2. resolvableDependencies 存放特殊的bean以供使用,如applicationContext,beanFactory等
3. beanPostProcessors 提供对各种注解的支持
4. ApplicationContextAwareProcessor 用来解析Aware接口
*/
prepareBeanFactory(beanFactory);
try {
/* 空实现提供给子类进行扩展.允许在上下文子类中对beanFactory进行增强,如web环境下需要更多功能.模板方法设计模式
beanFactory的一个扩展点
*/
postProcessBeanFactory(beanFactory);
/* 调用注册好的beanFactory后处理器,可以用来补充或修改BeanDefination.
beanFactory的一个扩展点
如提供@Bean,@Configuration等注解的支持
*/
invokeBeanFactoryPostProcessors(beanFactory);
/* 添加一些bean的后处理器,充当bean的扩展点,可以工作在bean的实例化,依赖注入,初始化阶段
从beanDefinationMap中找到实现了BeanPostProcessors接口的对象并注册,在后续需要相应功能时提供支持
如@Autowired,@Aspect,@PostContstruct
*/
registerBeanPostProcessors(beanFactory);
//BeanFactory增强结束-----------------------------------------------------------
// 实现国际化功能,查找容器中是否存在一个MessageSource的bean(实现相关接口),如果没有则提供空实现
initMessageSource();
/* 初始化事件广播器,查找容器中是否存在一个ApplicationEventMulticaster的bean,如果没有则新建默认的广播器
调用ApplicationContext.publishEvent()来发布事件
*/
initApplicationEventMulticaster();
// 空实现,供子类扩展使用.如spring boot中可以在此准备WebServer容器
onRefresh();
/* 注册事件监听器
监听器可以通过编程添加,从容器中获取,或来自与@EventListener的解析
实现ApplicationListener接口,重写其onApplicationEvent()方法即可接收事件
*/
registerListeners();
/* 完成非延迟单例bean的创建和初始化.其中会使用到上文中准备的beanPostProcessors
1. 单例池中缓存所有非延迟单例bean,对象的创建包含三个阶段:创建-依赖注入-初始化.每个阶段都有不同的bean后处理器参与
*/
finishBeanFactoryInitialization(beanFactory);
/* Last step: publish corresponding event.
1. 控制容器内需要生命周期管理的bean
2. 调用context的start,即可触发所有实现LifeCycle接口bean的start
*/
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
spring事件
Spring提供了事件机制,其本质是JDK提供的事件机制的应用,利用的是观察者设计模式。
在一个完整的事件体系中存在以下的角色:
- 事件:描述发生了什么事情、比如说请求处理完成、Spring 容器刷新完毕
- 事件源:事件的产生者、任何一个事件都必须有一个事件源。比如请求处理完成的事件源就是 DispatcherServlet 、Spring 容器刷新完毕的事件源就是 ApplicationContext
- 事件广播器:事件和事件监听器的桥梁、负责把事件通知给事件监听器
- 事件监听器:监听事件的发生、可以在监听器中做一些处理
事件
常见的事件可能就是 ApplicationContextEvent ,抽象类,继承了JDK的EventObject接口,起到包装事件源的作用。它的子类 ContextRefreshedEvent 是常见的事件类型、在 Spring 将所有非延迟加载的 bean 实例化之后发布。
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
监听器
ApplicationListener可以通用地声明它感兴趣的事件类型。当在Spring ApplicationContext中注册时,事件将被相应地过滤,只有匹配的事件对象才会调用侦听器
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
Q.E.D.