Spring的refresh方法-BeanFactoryPostProcessor番外篇(1

所有的内容都是基于 https://gitee.com/chris_777/spring-boot2.1.3 springboot 源码
main函数入口org.springframework.boot.tests.hibernate52.Hibernate52Application.main


BeanFactoryPostProcessor是一个接口,在refresh方法里面org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors 方法里面会使用到,我们来看看源码,是一个功能性接口,只有一个方法。根据注释,这个接口主要的作用是可以修改上下文中的bean工厂,可以加载bean的定义,甚至可以进行实例化操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@FunctionalInterface
public interface BeanFactoryPostProcessor {

/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

invokeBeanFactoryPostProcessors方法不仅调用了BeanFactoryPostProcessor接口的方法,还调用了BeanDefinitionRegistryPostProcessor接口。而这个接口中有一个很重要的实现类ConfigurationClassPostProcessor,这个类会解析@Component、@ComponentScan、@Import等注解。


那些@Service、@Controller注解,其实这些我们常用的Mvc注解,里面都是有@Component修饰的。


@ComponentScan这个很重要,构建SpringBoot项目的时候,Main函数需要使用该注解,来配置扫描的包路径。这样才能解析出这些类,并生成相应的bean定义,甚至实例化。


@Import也是很重要,需要解析该注解导入的AutoConfigurationImportSelector类,去解析spring.factories文件,用来加载需要自动装配的类。


BeanDefinitionRegistryPostProcessor接口继承了BeanFactoryPostProcessor接口,该接口主要的作用是修改Bean工厂,并且只能注册Bean的定义,不能进行初始化实例。invokeBeanFactoryPostProcessors 方法会优先调用BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,然后才会调用BeanFactoryPostProcessor接口中的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

我们来写一个简单的测试类,实践一下MyBeanDefinitionRegistryPostProcessor类实现了BeanDefinitionRegistryPostProcessor接口,该后置处理器的作用主要是扫描指定包路径下的Class类,然后判断是否有Chris注解,如果有的话加载Bean定义到容器中

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@Component
public class MyBeanDefinitionRegistryPostProcessor
implements BeanDefinitionRegistryPostProcessor {

protected final Log logger = LogFactory.getLog(MyBeanDefinitionRegistryPostProcessor.class);

/**
*参考 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(java.lang.String)
**/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath("org.springframework.boot.tests.hibernate52.mytest.custombean") + '/' + "**/*.class";
try {
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
logger.info("Scanning " + resource);
if (resource.isReadable()) {
MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(resource);
if (metadataReader.getAnnotationMetadata().hasAnnotation(Chris.class.getName())) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
sbd.setResource(resource);
registry.registerBeanDefinition(Chris.class.getName(), sbd);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}

}

/**
* 此方法的执行比 postProcessBeanDefinitionRegistry 晚
*
* @param beanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {

}


}

创建MyBeanFactoryPostProcessor类,实现BeanFactoryPostProcessor接口。该类主要实现注册实现了Chris注解的类的实例到容器中。(BeanFactoryPostProcessor的postProcessBeanFactory方法调用时机比BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法晚)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

/**
* 我们这里取出装有{@link Chris}注解的bean定义,进行实例化
* @param beanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] beanNamesForAnnotation = beanFactory.getBeanNamesForAnnotation(Chris.class);
for (String beanName : beanNamesForAnnotation) {
beanFactory.getBean(beanName);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Chris {

}

//实现InitializingBean接口,会在初始化之后调用
@Chris
public class CustomAnnotationTest implements InitializingBean {

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化好了>>>>>>>");
}

}

启动之后,控制台会打印

初始化好了>>>>>>>

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信