Package org.springframework.web.context.support

Source Code of org.springframework.web.context.support.AnnotationConfigWebApplicationContext

/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.web.context.support;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ContextLoader;

/**
* {@link org.springframework.web.context.WebApplicationContext WebApplicationContext}
* implementation which accepts annotated classes as input - in particular
* {@link org.springframework.context.annotation.Configuration @Configuration}-annotated
* classes, but also plain {@link org.springframework.stereotype.Component @Component}
* classes and JSR-330 compliant classes using {@code javax.inject} annotations. Allows
* for registering classes one by one (specifying class names as config location) as well
* as for classpath scanning (specifying base packages as config location).
*
* <p>This is essentially the equivalent of
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext
* AnnotationConfigApplicationContext} for a web environment.
*
* <p>To make use of this application context, the
* {@linkplain ContextLoader#CONTEXT_CLASS_PARAM "contextClass"} context-param for
* ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to
* the fully-qualified name of this class.
*
* <p>As of Spring 3.1, this class may also be directly instantiated and injected into
* Spring's {@code DispatcherServlet} or {@code ContextLoaderListener} when using the
* new {@link org.springframework.web.WebApplicationInitializer WebApplicationInitializer}
* code-based alternative to {@code web.xml}. See its Javadoc for details and usage examples.
*
* <p>Unlike {@link XmlWebApplicationContext}, no default configuration class locations
* are assumed. Rather, it is a requirement to set the
* {@linkplain ContextLoader#CONFIG_LOCATION_PARAM "contextConfigLocation"}
* context-param for {@link ContextLoader} and/or "contextConfigLocation" init-param for
* FrameworkServlet.  The param-value may contain both fully-qualified
* class names and base packages to scan for components. See {@link #loadBeanDefinitions}
* for exact details on how these locations are processed.
*
* <p>As an alternative to setting the "contextConfigLocation" parameter, users may
* implement an {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer} and set the
* {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
* context-param / init-param. In such cases, users should favor the {@link #refresh()}
* and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
* method, which is primarily for use by {@code ContextLoader}
*
* <p>Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}
* definitions will override ones defined in earlier loaded files. This can be leveraged
* to deliberately override certain bean definitions via an extra Configuration class.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
*/
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {

  private Class<?>[] annotatedClasses;

  private String[] basePackages;

  private BeanNameGenerator beanNameGenerator;

  private ScopeMetadataResolver scopeMetadataResolver;

  /**
   * {@inheritDoc}
   * <p>This implementation accepts delimited values in the form of fully-qualified
   * class names, (typically of {@code Configuration} classes) or fully-qualified
   * packages to scan for annotated classes. During {@link #loadBeanDefinitions}, these
   * locations will be processed in their given order, first attempting to load each
   * value as a class. If class loading fails (i.e. a {@code ClassNotFoundException}
   * occurs), the value is assumed to be a package and scanning is attempted.
   * <p>Note that this method exists primarily for compatibility with Spring's
   * {@link org.springframework.web.context.ContextLoader} and that if this application
   * context is being configured through an
   * {@link org.springframework.context.ApplicationContextInitializer}, use of the
   * {@link #register} and {@link #scan} methods are preferred.
   * @see #register(Class...)
   * @see #scan(String...)
   * @see #setConfigLocations(String[])
   * @see #loadBeanDefinitions(DefaultListableBeanFactory)
   */
  @Override
  public void setConfigLocation(String location) {
    super.setConfigLocation(location);
  }

  /**
   * {@inheritDoc}
   * <p>This implementation accepts individual location values as fully-qualified class
   * names (typically {@code @Configuration} classes) or fully-qualified packages to
   * scan. During {@link #loadBeanDefinitions}, these locations will be processed in
   * order, first attempting to load values as a class, and upon class loading failure
   * the value is assumed to be a package to be scanned.
   * <p>Note that this method exists primarily for compatibility with Spring's
   * {@link org.springframework.web.context.ContextLoader} and that if this application
   * context is being configured through an
   * {@link org.springframework.context.ApplicationContextInitializer}, use of the
   * {@link #register} and {@link #scan} methods are preferred.
   * @see #scan(String...)
   * @see #register(Class...)
   * @see #setConfigLocation(String)
   * @see #loadBeanDefinitions(DefaultListableBeanFactory)
   */
  @Override
  public void setConfigLocations(String[] locations) {
    super.setConfigLocations(locations);
  }

  /**
   * Register one or more annotated classes to be processed.
   * Note that {@link #refresh()} must be called in order for the context to fully
   * process the new class.
   * <p>Calls to {@link #register} are idempotent; adding the same
   * annotated class more than once has no additional effect.
   * @param annotatedClasses one or more annotated classes,
   * e.g. {@link Configuration @Configuration} classes
   * @see #scan(String...)
   * @see #loadBeanDefinitions(DefaultListableBeanFactory)
   * @see #setConfigLocation(String)
   * @see #refresh()
   */
  public void register(Class<?>... annotatedClasses) {
    Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
    this.annotatedClasses = annotatedClasses;
  }

  /**
   * Perform a scan within the specified base packages.
   * Note that {@link #refresh()} must be called in order for the context to
   * fully process the new class.
   * @param basePackages the packages to check for annotated classes
   * @see #loadBeanDefinitions(DefaultListableBeanFactory)
   * @see #register(Class...)
   * @see #setConfigLocation(String)
   * @see #refresh()
   */
  public void scan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    this.basePackages = basePackages;
  }

  /**
   * Register a {@link org.springframework.beans.factory.config.BeanDefinition} for
   * any classes specified by {@link #register(Class...)} and scan any packages
   * specified by {@link #scan(String...)}.
   * <p>For any values specified by {@link #setConfigLocation(String)} or
   * {@link #setConfigLocations(String[])}, attempt first to load each location as a
   * class, registering a {@code BeanDefinition} if class loading is successful,
   * and if class loading fails (i.e. a {@code ClassNotFoundException} is raised),
   * assume the value is a package and attempt to scan it for annotated classes.
   * <p>Enables the default set of annotation configuration post processors, such that
   * {@code @Autowired}, {@code @Required}, and associated annotations can be used.
   * <p>Configuration class bean definitions are registered with generated bean
   * definition names unless the {@code value} attribute is provided to the stereotype
   * annotation.
   * @see #register(Class...)
   * @see #scan(String...)
   * @see #setConfigLocation()
   * @see #setConfigLocations()
   * @see AnnotatedBeanDefinitionReader
   * @see ClassPathBeanDefinitionScanner
   */
  @Override
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
    reader.setEnvironment(this.getEnvironment());

    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
    scanner.setEnvironment(this.getEnvironment());

    BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
    ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
    if (beanNameGenerator != null) {
      reader.setBeanNameGenerator(beanNameGenerator);
      scanner.setBeanNameGenerator(beanNameGenerator);
    }
    if (scopeMetadataResolver != null) {
      reader.setScopeMetadataResolver(scopeMetadataResolver);
      scanner.setScopeMetadataResolver(scopeMetadataResolver);
    }

    if (!ObjectUtils.isEmpty(this.annotatedClasses)) {
      if (logger.isInfoEnabled()) {
        logger.info("Registering annotated classes: [" +
            StringUtils.arrayToCommaDelimitedString(this.annotatedClasses) + "]");
      }
      reader.register(this.annotatedClasses);
    }

    if (!ObjectUtils.isEmpty(this.basePackages)) {
      if (logger.isInfoEnabled()) {
        logger.info("Scanning base packages: [" +
            StringUtils.arrayToCommaDelimitedString(this.basePackages) + "]");
      }
      scanner.scan(this.basePackages);
    }

    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
      for (String configLocation : configLocations) {
        try {
          Class<?> clazz = getClassLoader().loadClass(configLocation);
          if (logger.isInfoEnabled()) {
            logger.info("Successfully resolved class for [" + configLocation + "]");
          }
          reader.register(clazz);
        }
        catch (ClassNotFoundException ex) {
          if (logger.isDebugEnabled()) {
            logger.debug("Could not load class for config location [" + configLocation +
                "] - trying package scan. " + ex);
          }
          int count = scanner.scan(configLocation);
          if (logger.isInfoEnabled()) {
            if (count == 0) {
              logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
            }
            else {
              logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
            }
          }
        }
      }
    }
  }

  public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
    this.beanNameGenerator = beanNameGenerator;
  }

  /**
   * Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
   * and/or {@link ClassPathBeanDefinitionScanner}, if any.
   * <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
   * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
   * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
   */
  protected BeanNameGenerator getBeanNameGenerator() {
    return this.beanNameGenerator;
  }

  /**
   * Set the {@link ScopeMetadataResolver} to use for detected bean classes.
   * <p>The default is an {@link AnnotationScopeMetadataResolver}.
   */
  public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
    this.scopeMetadataResolver = scopeMetadataResolver;
  }

  /**
   * Provide a custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader}
   * and/or {@link ClassPathBeanDefinitionScanner}, if any.
   * <p>Default is {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}.
   * @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver
   * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
   */
  protected ScopeMetadataResolver getScopeMetadataResolver() {
    return this.scopeMetadataResolver;
  }
}
TOP

Related Classes of org.springframework.web.context.support.AnnotationConfigWebApplicationContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.