001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.support; 018 019import java.io.IOException; 020import java.util.Collections; 021import java.util.Set; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.beans.factory.BeanDefinitionStoreException; 027import org.springframework.core.env.Environment; 028import org.springframework.core.env.EnvironmentCapable; 029import org.springframework.core.env.StandardEnvironment; 030import org.springframework.core.io.Resource; 031import org.springframework.core.io.ResourceLoader; 032import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 033import org.springframework.core.io.support.ResourcePatternResolver; 034import org.springframework.lang.Nullable; 035import org.springframework.util.Assert; 036 037/** 038 * Abstract base class for bean definition readers which implement 039 * the {@link BeanDefinitionReader} interface. 040 * 041 * <p>Provides common properties like the bean factory to work on 042 * and the class loader to use for loading bean classes. 043 * 044 * @author Juergen Hoeller 045 * @author Chris Beams 046 * @since 11.12.2003 047 * @see BeanDefinitionReaderUtils 048 */ 049public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable { 050 051 /** Logger available to subclasses. */ 052 protected final Log logger = LogFactory.getLog(getClass()); 053 054 private final BeanDefinitionRegistry registry; 055 056 @Nullable 057 private ResourceLoader resourceLoader; 058 059 @Nullable 060 private ClassLoader beanClassLoader; 061 062 private Environment environment; 063 064 private BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE; 065 066 067 /** 068 * Create a new AbstractBeanDefinitionReader for the given bean factory. 069 * <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry 070 * interface but also the ResourceLoader interface, it will be used as default 071 * ResourceLoader as well. This will usually be the case for 072 * {@link org.springframework.context.ApplicationContext} implementations. 073 * <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a 074 * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. 075 * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its 076 * environment will be used by this reader. Otherwise, the reader will initialize and 077 * use a {@link StandardEnvironment}. All ApplicationContext implementations are 078 * EnvironmentCapable, while normal BeanFactory implementations are not. 079 * @param registry the BeanFactory to load bean definitions into, 080 * in the form of a BeanDefinitionRegistry 081 * @see #setResourceLoader 082 * @see #setEnvironment 083 */ 084 protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) { 085 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 086 this.registry = registry; 087 088 // Determine ResourceLoader to use. 089 if (this.registry instanceof ResourceLoader) { 090 this.resourceLoader = (ResourceLoader) this.registry; 091 } 092 else { 093 this.resourceLoader = new PathMatchingResourcePatternResolver(); 094 } 095 096 // Inherit Environment if possible 097 if (this.registry instanceof EnvironmentCapable) { 098 this.environment = ((EnvironmentCapable) this.registry).getEnvironment(); 099 } 100 else { 101 this.environment = new StandardEnvironment(); 102 } 103 } 104 105 106 public final BeanDefinitionRegistry getBeanFactory() { 107 return this.registry; 108 } 109 110 @Override 111 public final BeanDefinitionRegistry getRegistry() { 112 return this.registry; 113 } 114 115 /** 116 * Set the ResourceLoader to use for resource locations. 117 * If specifying a ResourcePatternResolver, the bean definition reader 118 * will be capable of resolving resource patterns to Resource arrays. 119 * <p>Default is PathMatchingResourcePatternResolver, also capable of 120 * resource pattern resolving through the ResourcePatternResolver interface. 121 * <p>Setting this to {@code null} suggests that absolute resource loading 122 * is not available for this bean definition reader. 123 * @see org.springframework.core.io.support.ResourcePatternResolver 124 * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver 125 */ 126 public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { 127 this.resourceLoader = resourceLoader; 128 } 129 130 @Override 131 @Nullable 132 public ResourceLoader getResourceLoader() { 133 return this.resourceLoader; 134 } 135 136 /** 137 * Set the ClassLoader to use for bean classes. 138 * <p>Default is {@code null}, which suggests to not load bean classes 139 * eagerly but rather to just register bean definitions with class names, 140 * with the corresponding Classes to be resolved later (or never). 141 * @see Thread#getContextClassLoader() 142 */ 143 public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) { 144 this.beanClassLoader = beanClassLoader; 145 } 146 147 @Override 148 @Nullable 149 public ClassLoader getBeanClassLoader() { 150 return this.beanClassLoader; 151 } 152 153 /** 154 * Set the Environment to use when reading bean definitions. Most often used 155 * for evaluating profile information to determine which bean definitions 156 * should be read and which should be omitted. 157 */ 158 public void setEnvironment(Environment environment) { 159 Assert.notNull(environment, "Environment must not be null"); 160 this.environment = environment; 161 } 162 163 @Override 164 public Environment getEnvironment() { 165 return this.environment; 166 } 167 168 /** 169 * Set the BeanNameGenerator to use for anonymous beans 170 * (without explicit bean name specified). 171 * <p>Default is a {@link DefaultBeanNameGenerator}. 172 */ 173 public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) { 174 this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : DefaultBeanNameGenerator.INSTANCE); 175 } 176 177 @Override 178 public BeanNameGenerator getBeanNameGenerator() { 179 return this.beanNameGenerator; 180 } 181 182 183 @Override 184 public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { 185 Assert.notNull(resources, "Resource array must not be null"); 186 int count = 0; 187 for (Resource resource : resources) { 188 count += loadBeanDefinitions(resource); 189 } 190 return count; 191 } 192 193 @Override 194 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { 195 return loadBeanDefinitions(location, null); 196 } 197 198 /** 199 * Load bean definitions from the specified resource location. 200 * <p>The location can also be a location pattern, provided that the 201 * ResourceLoader of this bean definition reader is a ResourcePatternResolver. 202 * @param location the resource location, to be loaded with the ResourceLoader 203 * (or ResourcePatternResolver) of this bean definition reader 204 * @param actualResources a Set to be filled with the actual Resource objects 205 * that have been resolved during the loading process. May be {@code null} 206 * to indicate that the caller is not interested in those Resource objects. 207 * @return the number of bean definitions found 208 * @throws BeanDefinitionStoreException in case of loading or parsing errors 209 * @see #getResourceLoader() 210 * @see #loadBeanDefinitions(org.springframework.core.io.Resource) 211 * @see #loadBeanDefinitions(org.springframework.core.io.Resource[]) 212 */ 213 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { 214 ResourceLoader resourceLoader = getResourceLoader(); 215 if (resourceLoader == null) { 216 throw new BeanDefinitionStoreException( 217 "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available"); 218 } 219 220 if (resourceLoader instanceof ResourcePatternResolver) { 221 // Resource pattern matching available. 222 try { 223 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 224 int count = loadBeanDefinitions(resources); 225 if (actualResources != null) { 226 Collections.addAll(actualResources, resources); 227 } 228 if (logger.isTraceEnabled()) { 229 logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]"); 230 } 231 return count; 232 } 233 catch (IOException ex) { 234 throw new BeanDefinitionStoreException( 235 "Could not resolve bean definition resource pattern [" + location + "]", ex); 236 } 237 } 238 else { 239 // Can only load single resources by absolute URL. 240 Resource resource = resourceLoader.getResource(location); 241 int count = loadBeanDefinitions(resource); 242 if (actualResources != null) { 243 actualResources.add(resource); 244 } 245 if (logger.isTraceEnabled()) { 246 logger.trace("Loaded " + count + " bean definitions from location [" + location + "]"); 247 } 248 return count; 249 } 250 } 251 252 @Override 253 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { 254 Assert.notNull(locations, "Location array must not be null"); 255 int count = 0; 256 for (String location : locations) { 257 count += loadBeanDefinitions(location); 258 } 259 return count; 260 } 261 262}