概述
Spring BeanFactoryPostProcessor
Spring中有两种PostProcessor,BeanFactoryPostProcessor和BeanPostProcessor,本文主要介绍BeanFactoryPostProcessor
作用
Spring BeanFactoryPostProcessor
BeanFactoryPostProcessor 可以修改Spring上下文中bean的定义,修改bean的属性等。Spring上下文会自动查找BeanFactoryPostProcessor类型的bean定义,并在其他bean创建的时候调用写BeanFactoryPostProcessor的postProcessBeanFactory方法。
分类
BeanFactoryPostProcessor 又分为两种
- 常规 BeanFactoryPostProcessor
- BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,是一种比较特殊的BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor中定义的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法要优先于BeanFactoryPostProcessor的postProcessBeanFactory方法执行。
扩展实例
定义注解Handler
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Handler {
String code() default "";
}
定义类,并注解Handler
@Handler(code = "orderCreateHandler")
public class OrderHandler {
public void handle(){
System.out.println("handle invoked!");
}
}
扩展BeanDefinitionRegistryPostProcessor
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//这里可以自定义注解扫描,生成BeanDefinition并注册到spring上下文
//自定义代码可以参考Mybatis: org.mybatis.spring.mapper.MapperScannerConfigurer
//我们这里的逻辑很简单,扫描com.study.demo.handler包下,标有注解Handler的类,并注册到spring上下文
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.addIncludeFilter(new AnnotationTypeFilter(Handler.class));
scanner.scan("com.study.demo.handler");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//Nothing to do
}
}
启动Spring Boot 应用,可以看到标有Handler注解的类已经被注入到spring中
@SpringBootApplication
public class Demo implements CommandLineRunner {
//OrderHandler已经被注入到spring中,这里可以使用Autowired自动注入
@Autowired
private OrderHandler orderHandler;
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
@Override
public void run(String... args) throws Exception {
orderHandler.handle();
}
}
输出:
handle invoked!
Spring 实例
上面介绍的是一个简单的例子,下面看一下spring 中BeanDefinitionRegistryPostProcessor的应用。
ConfigurationClassPostProcessor 是一个BeanDefinitionRegistryPostProcessor,主要用于解析和注册配置类。我们以解析@Import(spring boot 自动配置的关键)注解为例,时序图如下:
核心代码如下:
org.springframework.context.annotation.ConfigurationClassParser#processImports
if (candidate.isAssignable(ImportSelector.class)) {
//第一种情况
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class <?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection < SourceClass > importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
//第二种情况
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class <?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
//第三种情况
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
@Import
上面介绍了@Import 的解析与注册,接下来介绍一下@Import 的使用。@Import 将类注册到spring容器中,其核心代码org.springframework.context.annotation.ConfigurationClassParser#processImports有三个分支逻辑,所以有三种使用方式
1. 引入java类
普通类
public class Foo {
public void foo(){
System.out.println("Foo.foo() invoked!");
}
}
@SpringBootApplication
@Import({Foo.class})
public class Demo implements CommandLineRunner {
@Autowired
private Foo foo;
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
@Override
public void run(String... args) throws Exception {
foo.foo();
}
}
输出:
Foo.foo() invoked!
配置类
public class Config {
@Bean
public Bar bar(){
return new Bar();
}
}
@SpringBootApplication
@Import({Config.class})
public class Demo implements CommandLineRunner {
@Autowired
private Bar bar;
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
@Override
public void run(String... args) throws Exception {
bar.bar();
}
}
输出:
Bar.bar() invoked!
2. 引入ImportBeanDefinitionRegistrar
public class FooBar {
public void fooBar() {
System.out.println("FooBar.fooBar() invoked!");
}
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(FooBar.class);
registry.registerBeanDefinition("fooBar", rootBeanDefinition);
}
}
@SpringBootApplication
@Import({MyImportBeanDefinitionRegistrar.class})
public class Demo implements CommandLineRunner {
@Autowired
private FooBar fooBar;
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
@Override
public void run(String... args) throws Exception {
fooBar.fooBar();
}
}
输出:
FooBar.fooBar() invoked!
3. 引入ImportSelector
spring 会将selectImports返回的结果注册成bean
public class BarFoo {
public void barFoo(){
System.out.println("BarFoo.barFoo() invoked!");
}
}
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.study.demo.domain.BarFoo"};
}
}
@SpringBootApplication
@Import({MyImportSelector.class})
public class Demo implements CommandLineRunner {
@Autowired
private BarFoo barFoo;
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
@Override
public void run(String... args) throws Exception {
barFoo.barFoo();
}
}
输出:
BarFoo.barFoo() invoked!
Spring Boot EnableAutoConfiguration
Spring Boot EnableAutoConfiguration 就是用第三种方式实现自动配置的
* EnableAutoConfiguration注解引入AutoConfigurationImportSelector
* AutoConfigurationImportSelector的selectImports查找所有META-INF/spring.factories里的类
* 查找META-INF/spring.factories里的类,通过SpringFactoriesLoader的方法loadFactoryNames
在EnableAutoConfiguration中引入AutoConfigurationImportSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
AutoConfigurationImportSelector 的 selectImports 方法,查询所有 META-INF/spring.factories的类。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//查找目标类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
getCandidateConfigurations方法中用到了SpringFactoriesLoader的loadFactoryNames方法,这个方法就是查找所有jar包中META-INF/spring.factories文件配置的类
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
最后
以上就是幽默啤酒为你收集整理的Spring BeanFactoryPostProcessorSpring BeanFactoryPostProcessor的全部内容,希望文章能够帮你解决Spring BeanFactoryPostProcessorSpring BeanFactoryPostProcessor所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复