Spring Framework
遇事不决上面找
1 beandifinition
1 BeanDefinitionRegistryPostProcessor的扩展
2 对ImportBeanDefinitionRegistrar扩展
3 对ImportBeanDefinitionRegistrar扩展
参考spring扩展点实战第一篇-beandifinition的自定义收集_tyd东的博客-CSDN博客
2 bean
1 InitializingBean
执行时机:
bean ioc之后 执行后置处理器的after方法之前
源码:
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
//这里
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
应用场景:
springmvc中就在AbstractHandlerMethodMapping的这个扩展点去加载映射信息,举例:假设你需要将某些信息提前预热到jvm缓存 可以在管理缓存的bean的这个扩展点去做
2 @PostConstruct
这个会上面提前一点 在before中执行,以spring的习惯是由一个处理器在初始化之前收集了该注解,后面在这里面进行反射调用,具体没去找,不研究这么细了,但是spring的这种思想就是如此,先收集 封装到一些地方 后面再在某个处理器去调用
3 disposableBean
执行时机:
收集是在bean的实例化过程中,执行是在容器销毁的时候 会来销毁bean
源码:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = System.getSecurityManager() != null ? this.getAccessControlContext() : null;
if (!mbd.isPrototype() && this.requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
this.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessors(), acc));
} else {
Scope scope = (Scope)this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessors(), acc));
}
}
}
这里收集,后面调用 就是spring的一贯思想
应用场景:
在bean销毁的时候 需要释放资源啥的,可以在这里扩展
4 aware
执行时机:
在bean的initializeBean方法里
源码:
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
}
}
应用场景:
暂时没找到 假设需要applicationContext可以直接注入进来,比较鸡肋
5 ApplicationListener
这就是基于一个事件发布订阅
源码
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
在refresh方法里 这个initApplicationEventMulticaster就是一个初始化一个事件管理器,后续发布事件和找到对应的监听器都是基于这个类做的,this.registerListeners()就是spring自己和开发定义好的监听器,最后finishrefreh就会发布一个contextRefreshed的事件,
应用场景:
很多开源框架需要基于spring的各种事件做处理 像nacos里客户端监听WebServerInitializedEvent向服务器注册
6 @bean和fatoryBean和registerBean()
适用场景:
@Bean和fatoryBean都是适用于创建复杂的bean或者这些类不是开发者自己写的,正常的bean都是通过反射
@Bean因为类不是开发者自己开发的类 是由别人开发好的,你只需要创建即可,
fatoryBean是适用开源框架生成一些复杂的类注入到spring.具体类也不由开发者自己创建,在注册成bd的时候 会改变它的beanClass属性变成框架的factoryBean(MapperFactoryBean),在实例化的时候 会根据getObject方法生成对应的代理对象
registerBean是自己向容器添加对象,这里面会注册一个bd,在getbean的时候会实例化它,这种用的也很少,因为添加别人开发的类 你用@bean就好了
源码
就不展示了,只知道@bean是改变fatory-method,那么以spring的习惯是在扫描的时候 判断有没有@bean注解 如果有的话 将该方法封装下放到一个地方 并且在注册bd的时候 去改变factory-method和beanname属性,在实例化的时候 调用到factory-method的时候 去调用对应的方法创建对象
fatory-bean: 就是有行代码判断是否实现了factoryBean 如果是 就调用getObject方法,这里就不详细展示了
3 springmvc
暂时想到的就是自己添加拦截器,过滤器,转换器啥的 其余的没想到
继承WebMvcConfigurationSupport
4 springboot
感觉用的最多的就是自定义starter
适用场景:
自己把bean写好,使用方引入了你的starer,bean会自己注入到spring容器中,不需要别人注入
源码:
spi的思想, 也是提供starer的开发者需要实现这个规范 那么它的类就能被springboot项目扫描到它的类 并变成bean ,因为spirngboot项目扫不到jar包的componetScan注解
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
demo代码:
pom中只需要引入一个boot-starter
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>tyd-study</artifactId>
<groupId>com.tyd.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<version>0.0.5-SNAPSHOT</version>
<artifactId>tyd-study-spring-starter</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
</dependencies>
</project>
定义好META-INF的spring.factories中加
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tyd.spring.starter.MyStarterConfig
package com.tyd.spring.starter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyStarterConfig {
@Bean
public MyStarerBean myStarerBean(){
return new MyStarerBean();
}
}
在install一下 再引入你的starter包 就能用你这个starer里的bean了