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