Spring注解式开发(四):Spring底层对BeanPostProcessor的应用

引言

上篇文章介绍了BeanPostProcessor的原理,这周加了一周的班,周末静下心来继续spring注解式开发的学习。

Spring提供了哪些BeanPostProcessor

spring为我们提供了很多BeanPostProcessor,使用开发工具可以看到下图,我们就挑几个介绍一下
在这里插入图片描述
这只是其中的一部分

1.ApplicationContextAwareProcessor的使用

ApplicationContextAwareProcessor是一个Spring内部工具,它实现了接口BeanPostProcessor,用于向实现了如下某种Aware接口的bean设置ApplicationContext中相应的属性:
通过ApplicationContextAwareProcessor源码中postProcessBeforeInitialization的实现可以看出只要我们的bean组件实现了以下接口就会为这个bean设置ApplicationContext中相应的属性:

  • EnvironmentAware 用于读取配置文件中的信息
  • EmbeddedValueResolverAware 获取Spring容器加载的 properties文件属性值
  • ResourceLoaderAware 获取资源加载器,获得外部资源文件
  • ApplicationEventPublisherAware ApplicationEventPublisherAware事件发布详解
  • MessageSourceAware Spring的MessageSource的作用
  • ApplicationContextAware 获取IOC容器
    那么如果我们的bean实现了相应的Aware接口,就会去执行invokeAwareInterfaces为bean设置ApplicationContext中相应的属性
class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}

	@Override
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;
		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareInterfaces(bean);
					return null;
				}
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}
}

那么我就举一个实现了ResourceLoaderAware接口的bean做一个测试

ResourceLoaderAware可以用来获取资源加载器,获得外部资源文件

//配置类
@Configuration
public class AwareConfig {
    @Bean
    public MyAwareBean myAwareBean(){
        return new MyAwareBean();
    }
}
//自定义组件实现ResourceLoaderAware
public class MyAwareBean implements ResourceLoaderAware {
    private ResourceLoader resourceLoader;
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }
}
//测试
@Test
    public void TestAwareProcessor(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AwareConfig.class);
        MyAwareBean bean = applicationContext.getBean(MyAwareBean.class);
        ResourceLoader resourceLoader = bean.getResourceLoader();
        System.out.println("resourceLoader:"+resourceLoader);
        Resource resource=resourceLoader.getResource("classpath:aware-test.txt");
        System.out.println("ResourceLoader加载的文件内容是:");
        String line=null;
        BufferedReader reader=new BufferedReader(new InputStreamReader(resource.getInputStream()));
        while((line=reader.readLine())!=null){
            System.out.println(line);
        }
        reader.close();
    }

测试结果(文字是aware-test.txt中的类容)

resourceLoader:org.springframework.context.annotation.AnnotationConfigApplicationContext@4c15e7fd: startup date [Sat Jan 12 15:34:33 CST 2019]; root of context hierarchy
ResourceLoader加载的文件内容是:
    致橡树
我如果爱你——
绝不学攀援的凌霄花,借你的高枝炫耀自己;
绝不学痴情的鸟儿,为绿荫重复单调的歌曲;
也不止象泉源,常年送来清凉的慰籍;也不止象险峰,
增加你的高度,衬托你的威仪。
甚至日光,甚至春雨,
不,这些都还不够,我必须是你近旁的一株木棉,
作为树的形象和你站在一起。
根,相握在地下;
叶,相触在云里。
每一阵风吹过,我们都互相致意,
但没有人,听懂我们的言语。
你有你的铜枝铁干,
象刀象剑也象戟;
我有我红硕的花朵,
象沉重的叹息,
又象英勇的火炬,
我们分担寒潮风雷霹雳;我们共享雾霭流岚虹霓;
仿佛永远分离,却又终身相依。
这才是伟大的爱情,坚贞就在这里――
爱,不仅爱你伟岸的身躯,
也爱你坚持的位置,足下的土地

其他的就不用举例了,用法基本都是类似的,主要要了解不同的Aware可以提供什么功能以及这些功能在开发中的用处,比如这个读取外部资源的就可以使用配置文件来给属性赋值,这样就可以做动态的配置

AutowiredAnnotationBeanPostProcessor介绍

这是一个解析bean中@Autowire注解的类,这个类实现了BeanPostProcessor接口
接下来看一下实现源码

@Override
public PropertyValues postProcessPropertyValues(
		PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
	//获取Autowire元数据
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		//将获取的元素注入到bean中
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

上面的代码我们先来看findAutowiringMetadata方法,其实这个方法我们可以不用关心,如何获取Autowire元数可以看看,其中的关键代码就是InjectionMetadata metadata =this.injectionMetadataCache.get(cacheKey);这句话。从这里我们知道他是从this.injectionMetadataCache,这是一个Map,key为beanName,value为注入元数据InjectionMetadata。即直接从这个Map中获取,那么接下来我们就要知道这个注入信息是什么时候放入到这个缓存Map上的。从findAutowiringMetadata代码上,我们看到this.injectionMetadataCache.put(cacheKey, metadata);这段代码,这代码就是把注入信息放到this.injectionMetadataCache上。那么,从这里我们可以猜测,在Bean实例化过程中findAutowiringMetadata()这个方法肯定被调用了多次。

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
	// 获取缓存的的key
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 根据缓存的key获取缓存中的metadata,此处我们在开发中也可以借鉴,使用hashMap做缓存来加速计算
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	//此处运用了双重检锁,单例模式也可以使用这种方式来保证线程间的单例模式
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				try {
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
				catch (NoClassDefFoundError err) {
					throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
							"] for autowiring metadata: could not find class that it depends on", err);
				}
			}
		}
	}
	return metadata;
}

当获取到元数据之后就开调用inject方法注入

public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> elementsToIterate =
			(this.checkedElements != null ? this.checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		boolean debug = logger.isDebugEnabled();
		for (InjectedElement element : elementsToIterate) {
			if (debug) {
				logger.debug("Processing injected element of bean '" + beanName + "': " + element);
			}
			//开始向bean中注入element
			element.inject(target, beanName, pvs);
		}
	}
}

接下来看一下AutowiredFieldElement.inject(target, beanName, pvs);

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				//创建一个依赖描述
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				try {
					//获取要注入的对象
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				synchronized (this) {
					//这段代码使用设置缓存的值的,可以不用关心
					if (!this.cached) {
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							registerDependentBeans(beanName, autowiredBeanNames);
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								if (beanFactory.containsBean(autowiredBeanName)) {
									if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
										this.cachedFieldValue = new ShortcutDependencyDescriptor(
												desc, autowiredBeanName, field.getType());
									}
								}
							}
						}
						else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			//当获取的值不是null时就开始注入
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

到此@Autowire注解大致原理就讲完了,其实其中还有很多细节,比如这个注解的的属性是什么时机注入到bean中的,后续再补充吧

结束语

下篇文章将介绍属性赋值和自动装配

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章