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.test.context.cache;
018
019import org.springframework.context.ApplicationContext;
020import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
021import org.springframework.test.context.MergedContextConfiguration;
022
023/**
024 * {@code ContextCache} defines the SPI for caching Spring
025 * {@link ApplicationContext ApplicationContexts} within the
026 * <em>Spring TestContext Framework</em>.
027 *
028 * <p>A {@code ContextCache} maintains a cache of {@code ApplicationContexts}
029 * keyed by {@link MergedContextConfiguration} instances, potentially configured
030 * with a {@linkplain ContextCacheUtils#retrieveMaxCacheSize maximum size} and
031 * a custom eviction policy.
032 *
033 * <h3>Rationale</h3>
034 * <p>Context caching can have significant performance benefits if context
035 * initialization is complex. Although the initialization of a Spring context
036 * itself is typically very quick, some beans in a context &mdash; for example,
037 * an embedded database or a {@code LocalContainerEntityManagerFactoryBean} for
038 * working with JPA &mdash; may take several seconds to initialize. Hence it
039 * often makes sense to perform that initialization only once per test suite or
040 * JVM process.
041 *
042 * @author Sam Brannen
043 * @author Juergen Hoeller
044 * @since 4.2
045 * @see ContextCacheUtils#retrieveMaxCacheSize()
046 */
047public interface ContextCache {
048
049        /**
050         * The name of the logging category used for reporting {@code ContextCache}
051         * statistics.
052         */
053        String CONTEXT_CACHE_LOGGING_CATEGORY = "org.springframework.test.context.cache";
054
055        /**
056         * The default maximum size of the context cache: {@value}.
057         * @since 4.3
058         * @see #MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME
059         */
060        int DEFAULT_MAX_CONTEXT_CACHE_SIZE = 32;
061
062        /**
063         * System property used to configure the maximum size of the {@link ContextCache}
064         * as a positive integer. May alternatively be configured via the
065         * {@link org.springframework.core.SpringProperties} mechanism.
066         * <p>Note that implementations of {@code ContextCache} are not required to
067         * actually support a maximum cache size. Consult the documentation of the
068         * corresponding implementation for details.
069         * @since 4.3
070         * @see #DEFAULT_MAX_CONTEXT_CACHE_SIZE
071         */
072        String MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME = "spring.test.context.cache.maxSize";
073
074
075        /**
076         * Determine whether there is a cached context for the given key.
077         * @param key the context key (never {@code null})
078         * @return {@code true} if the cache contains a context with the given key
079         */
080        boolean contains(MergedContextConfiguration key);
081
082        /**
083         * Obtain a cached {@code ApplicationContext} for the given key.
084         * <p>The {@linkplain #getHitCount() hit} and {@linkplain #getMissCount() miss}
085         * counts must be updated accordingly.
086         * @param key the context key (never {@code null})
087         * @return the corresponding {@code ApplicationContext} instance, or {@code null}
088         * if not found in the cache
089         * @see #remove
090         */
091        ApplicationContext get(MergedContextConfiguration key);
092
093        /**
094         * Explicitly add an {@code ApplicationContext} instance to the cache
095         * under the given key, potentially honoring a custom eviction policy.
096         * @param key the context key (never {@code null})
097         * @param context the {@code ApplicationContext} instance (never {@code null})
098         */
099        void put(MergedContextConfiguration key, ApplicationContext context);
100
101        /**
102         * Remove the context with the given key from the cache and explicitly
103         * {@linkplain org.springframework.context.ConfigurableApplicationContext#close() close}
104         * it if it is an instance of {@code ConfigurableApplicationContext}.
105         * <p>Generally speaking, this method should be called to properly evict
106         * a context from the cache (e.g., due to a custom eviction policy) or if
107         * the state of a singleton bean has been modified, potentially affecting
108         * future interaction with the context.
109         * <p>In addition, the semantics of the supplied {@code HierarchyMode} must
110         * be honored. See the Javadoc for {@link HierarchyMode} for details.
111         * @param key the context key; never {@code null}
112         * @param hierarchyMode the hierarchy mode; may be {@code null} if the context
113         * is not part of a hierarchy
114         */
115        void remove(MergedContextConfiguration key, HierarchyMode hierarchyMode);
116
117        /**
118         * Determine the number of contexts currently stored in the cache.
119         * <p>If the cache contains more than {@code Integer.MAX_VALUE} elements,
120         * this method must return {@code Integer.MAX_VALUE}.
121         */
122        int size();
123
124        /**
125         * Determine the number of parent contexts currently tracked within the cache.
126         */
127        int getParentContextCount();
128
129        /**
130         * Get the overall hit count for this cache.
131         * <p>A <em>hit</em> is any access to the cache that returns a non-null
132         * context for the queried key.
133         */
134        int getHitCount();
135
136        /**
137         * Get the overall miss count for this cache.
138         * <p>A <em>miss</em> is any access to the cache that returns a {@code null}
139         * context for the queried key.
140         */
141        int getMissCount();
142
143        /**
144         * Reset all state maintained by this cache including statistics.
145         * @see #clear()
146         * @see #clearStatistics()
147         */
148        void reset();
149
150        /**
151         * Clear all contexts from the cache, clearing context hierarchy information as well.
152         */
153        void clear();
154
155        /**
156         * Clear hit and miss count statistics for the cache (i.e., reset counters to zero).
157         */
158        void clearStatistics();
159
160        /**
161         * Log the statistics for this {@code ContextCache} at {@code DEBUG} level
162         * using the {@value #CONTEXT_CACHE_LOGGING_CATEGORY} logging category.
163         * <p>The following information should be logged.
164         * <ul>
165         * <li>name of the concrete {@code ContextCache} implementation</li>
166         * <li>{@linkplain #size}</li>
167         * <li>{@linkplain #getParentContextCount() parent context count}</li>
168         * <li>{@linkplain #getHitCount() hit count}</li>
169         * <li>{@linkplain #getMissCount() miss count}</li>
170         * <li>any other information useful for monitoring the state of this cache</li>
171         * </ul>
172         */
173        void logStatistics();
174
175}