📄 abstractautowirecapablebeanfactory.java
字号:
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
}
return filtered;
}
}
/**
* Determine whether the given bean property is excluded from dependency checks.
* <p>This implementation excludes properties defined by CGLIB and
* properties whose type matches an ignored dependency type or which
* are defined by an ignored dependency interface.
* @param pd the PropertyDescriptor of the bean property
* @return whether the bean property is excluded
* @see #ignoreDependencyType(Class)
* @see #ignoreDependencyInterface(Class)
*/
protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
}
/**
* Perform a dependency check that all properties exposed have been set,
* if desired. Dependency checks can be objects (collaborating beans),
* simple (primitives and String), or all (both).
* @param beanName the name of the bean
* @param mbd the merged bean definition the bean was created with
* @param pds the relevant property descriptors for the target bean
* @param pvs the property values to be applied to the bean
* @see #isExcludedFromDependencyCheck(java.beans.PropertyDescriptor)
*/
protected void checkDependencies(
String beanName, RootBeanDefinition mbd, PropertyDescriptor[] pds, PropertyValues pvs)
throws UnsatisfiedDependencyException {
int dependencyCheck = mbd.getDependencyCheck();
for (int i = 0; i < pds.length; i++) {
if (pds[i].getWriteMethod() != null && !pvs.contains(pds[i].getName())) {
boolean isSimple = BeanUtils.isSimpleProperty(pds[i].getPropertyType());
boolean unsatisfied = (dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_ALL) ||
(isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_SIMPLE) ||
(!isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
if (unsatisfied) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, pds[i].getName(),
"Set this property value or disable dependency checking for this bean.");
}
}
}
}
/**
* Apply the given property values, resolving any runtime references
* to other beans in this bean factory. Must use deep copy, so we
* don't permanently modify this property.
* @param beanName the bean name passed for better exception information
* @param mbd the merged bean definition
* @param bw the BeanWrapper wrapping the target object
* @param pvs the new property values
*/
protected void applyPropertyValues(
String beanName, RootBeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
MutablePropertyValues mpvs = null;
List original = null;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this, beanName, mbd, bw);
// Create a deep copy, resolving any references for values.
BeanWrapperImpl bwi = (bw instanceof BeanWrapperImpl ? (BeanWrapperImpl) bw : null);
List deepCopy = new ArrayList(original.size());
boolean resolveNecessary = false;
for (Iterator it = original.iterator(); it.hasNext();) {
PropertyValue pv = (PropertyValue) it.next();
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue =
valueResolver.resolveValueIfNecessary("bean property '" + propertyName + "'", originalValue);
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (bwi != null && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
pv.setConvertedValue(bwi.convertForProperty(resolvedValue, propertyName));
}
deepCopy.add(pv);
}
else if (originalValue instanceof TypedStringValue &&
bwi != null && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
pv.setConvertedValue(bwi.convertForProperty(resolvedValue, propertyName));
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(propertyName, resolvedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be <code>null</code>, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
/**
* Give a bean a chance to react now all its properties are set,
* and a chance to know about its owning bean factory (this object).
* This means checking whether the bean implements InitializingBean or defines
* a custom init method, and invoking the necessary callback(s) if it does.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with
* (can also be <code>null</code>, if given an existing bean instance)
* @throws Throwable if thrown by init methods or by the invocation process
* @see #invokeCustomInitMethod
*/
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
throws Throwable {
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && mbd.getInitMethodName() != null) {
invokeCustomInitMethod(
beanName, bean, mbd.getInitMethodName(), mbd.isEnforceInitMethod());
}
}
/**
* Invoke the specified custom init method on the given bean.
* Called by invokeInitMethods.
* <p>Can be overridden in subclasses for custom resolution of init
* methods with arguments.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param initMethodName the name of the custom init method
* @param enforceInitMethod indicates whether the defined init method needs to exist
* @see #invokeInitMethods
*/
protected void invokeCustomInitMethod(
String beanName, Object bean, String initMethodName, boolean enforceInitMethod) throws Throwable {
Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
if (initMethod == null) {
if (enforceInitMethod) {
throw new NoSuchMethodException("Couldn't find an init method named '" + initMethodName +
"' on bean with name '" + beanName + "'");
}
else {
// Ignore non-existent default lifecycle methods.
return;
}
}
if (!Modifier.isPublic(initMethod.getModifiers()) ||
!Modifier.isPublic(initMethod.getDeclaringClass().getModifiers())) {
initMethod.setAccessible(true);
}
try {
initMethod.invoke(bean, (Object[]) null);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
/**
* Applies the <code>postProcessAfterInitialization</code> callback of all
* registered BeanPostProcessors, giving them a chance to post-process the
* object obtained from FactoryBeans (for example, to auto-proxy them).
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
/**
* Overridden to clear FactoryBean instance cache as well.
*/
protected void removeSingleton(String beanName) {
super.removeSingleton(beanName);
this.factoryBeanInstanceCache.remove(beanName);
}
//---------------------------------------------------------------------
// Template methods to be implemented by subclasses
//---------------------------------------------------------------------
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* <p>If a subclass cannot obtain information about bean names by type,
* a corresponding exception should be thrown.
* @param beanName the name of the bean that is about to be wired
* @param requiredType the type of the autowired property or argument
* @return a Map of candidate names and candidate instances that match
* the required type (never <code>null</code>)
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map findAutowireCandidates(String beanName, Class requiredType) throws BeansException {
Map result = findMatchingBeans(requiredType);
return (result != null ? result : Collections.EMPTY_MAP);
}
/**
* Find bean instances that match the required type. Called by autowiring.
* @param requiredType the type of the beans to look up
* @return a Map of bean names and bean instances that match the required type,
* or <code>null</code> if none found
* @throws BeansException in case of errors
* @deprecated as of Spring 2.0.1: Override <code>findAutowireCandidates</code> instead
*/
protected Map findMatchingBeans(Class requiredType) throws BeansException {
throw new FatalBeanException("Bean lookup by type not supported by this factory");
}
//---------------------------------------------------------------------
// Inner classes that serve as internal helpers
//---------------------------------------------------------------------
/**
* Subclass of ConstructorResolver that delegates to surrounding
* AbstractAutowireCapableBeanFactory facilities.
*/
private class ConstructorResolverAdapter extends ConstructorResolver {
public ConstructorResolverAdapter() {
super(AbstractAutowireCapableBeanFactory.this, getInstantiationStrategy());
}
protected Map findAutowireCandidates(String beanName, Class requiredType) throws BeansException {
return AbstractAutowireCapableBeanFactory.this.findAutowireCandidates(beanName, requiredType);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -