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