001/* 002 * Copyright 2002-2018 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.context.annotation; 018 019import org.springframework.beans.factory.support.BeanNameGenerator; 020import org.springframework.beans.factory.support.DefaultListableBeanFactory; 021import org.springframework.context.support.GenericApplicationContext; 022import org.springframework.core.env.ConfigurableEnvironment; 023import org.springframework.util.Assert; 024 025/** 026 * Standalone application context, accepting annotated classes as input - in particular 027 * {@link Configuration @Configuration}-annotated classes, but also plain 028 * {@link org.springframework.stereotype.Component @Component} types and JSR-330 compliant 029 * classes using {@code javax.inject} annotations. Allows for registering classes one by 030 * one using {@link #register(Class...)} as well as for classpath scanning using 031 * {@link #scan(String...)}. 032 * 033 * <p>In case of multiple {@code @Configuration} classes, @{@link Bean} methods defined in 034 * later classes will override those defined in earlier classes. This can be leveraged to 035 * deliberately override certain bean definitions via an extra {@code @Configuration} 036 * class. 037 * 038 * <p>See @{@link Configuration}'s javadoc for usage examples. 039 * 040 * @author Juergen Hoeller 041 * @author Chris Beams 042 * @since 3.0 043 * @see #register 044 * @see #scan 045 * @see AnnotatedBeanDefinitionReader 046 * @see ClassPathBeanDefinitionScanner 047 * @see org.springframework.context.support.GenericXmlApplicationContext 048 */ 049public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { 050 051 private final AnnotatedBeanDefinitionReader reader; 052 053 private final ClassPathBeanDefinitionScanner scanner; 054 055 056 /** 057 * Create a new AnnotationConfigApplicationContext that needs to be populated 058 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}. 059 */ 060 public AnnotationConfigApplicationContext() { 061 this.reader = new AnnotatedBeanDefinitionReader(this); 062 this.scanner = new ClassPathBeanDefinitionScanner(this); 063 } 064 065 /** 066 * Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory. 067 * @param beanFactory the DefaultListableBeanFactory instance to use for this context 068 */ 069 public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { 070 super(beanFactory); 071 this.reader = new AnnotatedBeanDefinitionReader(this); 072 this.scanner = new ClassPathBeanDefinitionScanner(this); 073 } 074 075 /** 076 * Create a new AnnotationConfigApplicationContext, deriving bean definitions 077 * from the given annotated classes and automatically refreshing the context. 078 * @param annotatedClasses one or more annotated classes, 079 * e.g. {@link Configuration @Configuration} classes 080 */ 081 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { 082 this(); 083 register(annotatedClasses); 084 refresh(); 085 } 086 087 /** 088 * Create a new AnnotationConfigApplicationContext, scanning for bean definitions 089 * in the given packages and automatically refreshing the context. 090 * @param basePackages the packages to check for annotated classes 091 */ 092 public AnnotationConfigApplicationContext(String... basePackages) { 093 this(); 094 scan(basePackages); 095 refresh(); 096 } 097 098 099 /** 100 * Propagates the given custom {@code Environment} to the underlying 101 * {@link AnnotatedBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}. 102 */ 103 @Override 104 public void setEnvironment(ConfigurableEnvironment environment) { 105 super.setEnvironment(environment); 106 this.reader.setEnvironment(environment); 107 this.scanner.setEnvironment(environment); 108 } 109 110 /** 111 * Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader} 112 * and/or {@link ClassPathBeanDefinitionScanner}, if any. 113 * <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}. 114 * <p>Any call to this method must occur prior to calls to {@link #register(Class...)} 115 * and/or {@link #scan(String...)}. 116 * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator 117 * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator 118 */ 119 public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { 120 this.reader.setBeanNameGenerator(beanNameGenerator); 121 this.scanner.setBeanNameGenerator(beanNameGenerator); 122 getBeanFactory().registerSingleton( 123 AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator); 124 } 125 126 /** 127 * Set the {@link ScopeMetadataResolver} to use for detected bean classes. 128 * <p>The default is an {@link AnnotationScopeMetadataResolver}. 129 * <p>Any call to this method must occur prior to calls to {@link #register(Class...)} 130 * and/or {@link #scan(String...)}. 131 */ 132 public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { 133 this.reader.setScopeMetadataResolver(scopeMetadataResolver); 134 this.scanner.setScopeMetadataResolver(scopeMetadataResolver); 135 } 136 137 @Override 138 protected void prepareRefresh() { 139 this.scanner.clearCache(); 140 super.prepareRefresh(); 141 } 142 143 144 //--------------------------------------------------------------------- 145 // Implementation of AnnotationConfigRegistry 146 //--------------------------------------------------------------------- 147 148 /** 149 * Register one or more annotated classes to be processed. 150 * <p>Note that {@link #refresh()} must be called in order for the context 151 * to fully process the new classes. 152 * @param annotatedClasses one or more annotated classes, 153 * e.g. {@link Configuration @Configuration} classes 154 * @see #scan(String...) 155 * @see #refresh() 156 */ 157 public void register(Class<?>... annotatedClasses) { 158 Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); 159 this.reader.register(annotatedClasses); 160 } 161 162 /** 163 * Perform a scan within the specified base packages. 164 * <p>Note that {@link #refresh()} must be called in order for the context 165 * to fully process the new classes. 166 * @param basePackages the packages to check for annotated classes 167 * @see #register(Class...) 168 * @see #refresh() 169 */ 170 public void scan(String... basePackages) { 171 Assert.notEmpty(basePackages, "At least one base package must be specified"); 172 this.scanner.scan(basePackages); 173 } 174 175}