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