One instance per Injector. Also see @Singleton. Introduction from the author: Implementation of this class seems unreasonably complicated at the first sight. I fully agree with you, that the beast below is very complex and it's hard to reason on how does it work or not. S
| 61 | * @author timofeyb (Timothy Basanov) |
| 62 | */ |
| 63 | public class SingletonScope implements Scope { |
| 64 | |
| 65 | /** A sentinel value representing null. */ |
| 66 | private static final Object NULL = new Object(); |
| 67 | |
| 68 | /** |
| 69 | * Allows us to detect when circular proxies are necessary. It's only used during singleton |
| 70 | * instance initialization, after initialization direct access through volatile field is used. |
| 71 | * |
| 72 | * <p>NB: Factory uses {@link Key}s as a user locks ids, different injectors can share them. |
| 73 | * Cycles are detected properly as cycle detection does not rely on user locks ids, but error |
| 74 | * message generated could be less than ideal. |
| 75 | */ |
| 76 | // TODO(user): we may use one factory per injector tree for optimization reasons |
| 77 | private static final CycleDetectingLockFactory<Key<?>> cycleDetectingLockFactory = |
| 78 | new CycleDetectingLockFactory<Key<?>>(); |
| 79 | |
| 80 | /** |
| 81 | * Provides singleton scope with the following properties: |
| 82 | * |
| 83 | * <ul> |
| 84 | * <li>creates no more than one instance per Key as a creator is used no more than once |
| 85 | * <li>result is cached and returned quickly on subsequent calls |
| 86 | * <li>exception in a creator is not treated as instance creation and is not cached |
| 87 | * <li>creates singletons in parallel whenever possible |
| 88 | * <li>waits for dependent singletons to be created even across threads and when dependencies |
| 89 | * are shared as long as no circular dependencies are detected |
| 90 | * <li>returns circular proxy only when circular dependencies are detected |
| 91 | * <li>aside from that, blocking synchronization is only used for proxy creation and |
| 92 | * initialization |
| 93 | * </ul> |
| 94 | * |
| 95 | * @see CycleDetectingLockFactory |
| 96 | */ |
| 97 | @Override |
| 98 | public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) { |
| 99 | /** Locking strategy: */ |
| 100 | return new Provider<T>() { |
| 101 | /** |
| 102 | * The lazily initialized singleton instance. Once set, this will either have type T or will |
| 103 | * be equal to NULL. Would never be reset to null. |
| 104 | * |
| 105 | * <p>Locking strategy: double-checked locking for quick exit when scope is initialized. |
| 106 | */ |
| 107 | volatile Object instance; |
| 108 | |
| 109 | /** |
| 110 | * Circular proxies are used when potential deadlocks are detected. Guarded by itself. |
| 111 | * ConstructionContext is not thread-safe, so each call should be synchronized. |
| 112 | * |
| 113 | * <p>Locking strategy: manipulations with proxies list or instance initialization. |
| 114 | */ |
| 115 | final ConstructionContext<T> constructionContext = new ConstructionContext<>(); |
| 116 | |
| 117 | /** |
| 118 | * For each binding there is a separate lock that we hold during object creation. |
| 119 | * |
| 120 | * <p>Locking strategy: singleton instance creation. |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…