Spring 容器相关知识
一、Spring InitializingBean
Spring 为Bean提供了两种初始化方式:
1.通过实现InitializingBean 接口后实现afterPropertiesSet方法,在其中指定初始化业务逻辑。
2.通过在配置中指定init-method实现bean的初始化方法 。
afterPropertiesSet方法与init-method调用的先后顺序
1.如果afterPropertiesSet方法和init-method同时存在,先调用afterPropertiesSet方法,后调用init-method。如果调用afterPropertiesSet方法出错,则不会调用init-method。
通过AbstractAutowireCapableBeanFactory中的invokeInitMethods方法可以看出两者的调用顺序:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
//调用afterPropertiesSet方法
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
//调用init-method方法
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
2.afterPropertiesSet方法是直接调用,比通过反射调用的init-method效率要高,但是init-method消除了对Spring的依赖。
二、Spring BeanFactoryPostProcessor | BeanPostProcessor
1.BeanPostProcessor : Bean的后置处理器的postProcessorBeforeInitailization方法是在bean实例化,依赖注入之后及自定义初始化方法(例如:配置文件中bean标签添加init-method属性指定Java类中初始化方法、@PostConstruct注解指定初始化方法,Java类实现InitailztingBean接口)之前调用。
2.后置处理器的postProcessorAfterInitailization方法是在bean实例化、依赖注入及自定义初始化方法之后调用。实现对Bean的再加工,属性修改和生成代理。
3.BeanPostProcessor 与 InitializingBean和DisposableBean的区别:
BeanPostProcessor将对所有的Bean起作用,即所有的bean初始化前后都会回调BeanPostProcessor实现类,InitializingBean 和 DisposableBean 针对单个bean,即只有在对应的bean实现了InitializingBean或DisposableBean接口才会对其进行回调。
三、BeanDefinitionRegistryPostProcessor
1.通过postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 可以让我们实现自定义的注册bean定义的逻辑。
public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition helloBean = new RootBeanDefinition(Hello.class);
//新增Bean定义
registry.registerBeanDefinition("hello", helloBean);
}
}
2.与ClassPathScanningCandidateComponentProvider配合使用,根据一定的规则扫描类路径下满足特定条件的Class来作为候选的bean定义。
列:扫描指定包及其子包下面的所有非接口和非抽象类
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
boolean useDefaultFilters = false;//是否使用默认的filter,使用默认的filter意味着只扫描那些类上拥有Component、Service、Repository或Controller注解的类。
String basePackage = "com.elim.learn.spring.bean";
ClassPathScanningCandidateComponentProvider beanScanner = new ClassPathScanningCandidateComponentProvider(useDefaultFilters);
TypeFilter includeFilter = new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
return metadataReader.getClassMetadata().isConcrete();
}
};
beanScanner.addIncludeFilter(includeFilter);
Set<BeanDefinition> beanDefinitions = beanScanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : beanDefinitions) {
//beanName通常由对应的BeanNameGenerator来生成,比如Spring自带的AnnotationBeanNameGenerator、DefaultBeanNameGenerator等,也可以自己实现。
String beanName = beanDefinition.getBeanClassName();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
补充:
- InitializingBean 和 DisposableBean 只针对单个的Bean
- BeanPostProcessor: Bean的后置处理器,处理对象是Bean
- BeanFactoryPostProcessor : BeanFactory的后置处理器,处理对象是BeanFactory