引言
上篇文章介绍了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中的,后续再补充吧
结束语
下篇文章将介绍属性赋值和自动装配