其实你找不到错误不代表错误不存在,同样你看不到技术比你牛的人并不代表世界上没有技术比你牛的人。
spring 中提供两种bean扩展实现BeanFactoryPostProcessor 和BeanPostProcessor。
BeanFactoryPostProcessor
BeanFactory的后置处理器,它的主要功能是参与BeanFactory的建造,通过BeanFactoryPostProcessor可以实现 @ComponentScans扫包、Properties配置加载等功能。下图是spring几个基本后置处理器。
7.BeanFactoryPostProcessor.png- ConfigurationClassPostProcessor:用于解析加了@Configuration的配置类,解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。其入口函数如下:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
该方法做了两件事。一保障processConfigBeanDefinitions一次处理;二、调用方法processConfigBeanDefinitions 。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
logger.debug("has already been processed as a configuration class: " );
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//省略排序、非空判断、环境准备等
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(/*省略*/);
//省略
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader( /*省略*/);
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//省略
for (String candidateName : newCandidateNames) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
candidateNames = newCandidateNames;
}
while (!candidates.isEmpty());
// ...
}
通过源码分析可以看的核心代码分为三部分,以是判断是否为配置类
ConfigurationClassUtils.checkConfigurationClassCandidate
//具体实现:
// full:完成匹配,识别注解 @Configuration
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
// 候选匹配
// 优先判断注解 @Component、@ComponentScan、@Import、@ImportResource
// 最后判断 @Bean 注解
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
// 接口中的注解不考虑
if (metadata.isInterface()) {
return false;
}
// 任意candidateIndicators注解标记的类
// candidateIndicators具体值有:Component、ComponentScan、Import、ImportResource
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
- PropertyResourceConfigurer 使用 ProperResource 自定义 bean 配置信息,核心源码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
processProperties(beanFactory, mergedProps);
}
PropertyResourceConfigurer 主要做了三件事。
- 合并属性
- 转换类型
- 处理属性
- CustomAutowireConfigurer 配置自定义自动装配类,CustomAutowireConfigurer是一个BeanFactoryPostProcessor,允许方便地注册自定义autowire限定符类型。即使没有使用Spring的@Qualifier注解
BeanPostProcessor
Bean后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。接口的源码如下
public interface BeanPostProcessor {
/**
* 在 init-method 或 afterPropertiesSet 等初始化操作之前构造一个新实例返回
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 在 init-method 或 afterPropertiesSet 等初始化操作之后构造一个新实例返回
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
类似修改bean配置信息、bean有效性验证等可以在postProcessBeforeInitialization实现; 一般AOP、代理等都在postProcessAfterInitialization阶段完成。
7.BeanPostProcessor.png上图显示了几个BeanPostProcessor的实现:
- AbstractAutoProxyCreator 创建代理,在 postProcessBeforeInitialization方法实现代理,源码如下
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
通过 wrapIfNecessary 方法重新封装bean。wrapIfNecessary 方法包括核心代码:
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
最后挑战到 createProxy 方法
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// ...
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
//todo 设置代理类型
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// ...
return proxyFactory.getProxy(getProxyClassLoader());
}
- LoadTimeWeaverAwareProcessor 代码织入处理器
从织入切面的方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入。编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中;而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;运行期织入则是采用CGLib工具或JDK动态代理进行切面的织入。
AspectJ采用编译期织入和类加载期织入的方式织入切面,是语言级的AOP实现,提供了完备的AOP支持。它用AspectJ语言定义切面,在编译期或类加载期将切面织入到Java类中。
AspectJ提供了两种切面织入方式,第一种通过特殊编译器,在编译期,将AspectJ语言编写的切面类织入到Java类中,可以通过一个Ant或Maven任务来完成这个操作;第二种方式是类加载期织入,也简称为LTW(Load Time Weaving)
核心代码:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LoadTimeWeaverAware) {
LoadTimeWeaver ltw = this.loadTimeWeaver;
if (ltw == null) {
Assert.state(this.beanFactory != null,
"BeanFactory required if no LoadTimeWeaver explicitly specified");
ltw = this.beanFactory.getBean(
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
}
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
}
return bean;
}
总结
- BeanFactoryPostProcessor 工厂后置处理器
- BeanPostProcessor bean 后置处理器
- LoadTimeWeaver 类加载期织入
- AspectJ 切面编程三种方式
网友评论