在使用spring 自动注入对象通常会用到@Autowired (spring 自定义注解)、@Resource (JSR-250规范定义的注解) 两个注解,在使用中@Autowired 支持 required = false 的设置可以允许注入对象为null,而@Resource 不支持该特性 (王侯将相宁有种乎?), 手动扩展spring使其支持null对象注入。
探究源码
// @Resource注解使用的是CommonAnnotationBeanPostProcessor处理器
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
/**
* 通过注入对象的名称从BeanFactory提取bean 对象
*/
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
throws BeansException {
Object resource;
Set autowiredBeanNames;
String name = element.name;
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet();
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
if (beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
}
扩展BeanPostProcessor
/**
* 直接继承CommonAnnotationBeanPostProcessor
* 作为BeanPostProcessor组件加载
*/
@Component
public class AutoResourceNull extends CommonAnnotationBeanPostProcessor {
/**
* 重写autowireResource方法。
* 在获取注入对象是如果为null捕获异常从而返回null对象,不影响spring 容器加载
*/
@Override
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName) throws BeansException {
Object obj = null;
try {
obj = super.autowireResource(factory, element, requestingBeanName);
} catch (Exception e) {
System.err.println(e.getMessage());
}
return obj;
}
}
通过重写CommonAnnotationBeanPostProcessor在对象注入前,重写该类中autowireResource 方法,在BeanFactory中找不到该对象是默认返回null对象给到引用方,从而不影响这个spring容器的加载,多数情况下用于单元测试阶段 (因为不想因为不相干的bean对象找不到从而影响整个spring容器的加载)。有一个缺点就是不能像@Autowired那样细粒度控制到具体某个对象允许为null,这里相当于给@Resource加了个全局开关。
实现@Autowired的全局允许为null的扩展
/**
* @Autowired 和 @Inject 使用的是 AutowiredAnnotationBeanPostProcessor 处理器
*/
@Component
public class AppTest extends AutowiredAnnotationBeanPostProcessor {
/**
* 同理,在获取bean对象时捕获异常返回null对象
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
try {
pvs = super.postProcessPropertyValues(pvs, pds, bean, beanName);
} catch (BeanCreationException e) {
System.err.println(e.getMessage());
}
return pvs;
}
}