2. codecentric AG
Singleton pattern
things we sometimes forget
Dependency injection / Inversion of Control
Paired with Singleton
Example without third party library
TOPICS
3. codecentric AG
What Singleton pattern does?
Implementation examples
Wrong implementations
Implementations that look okay
Right implementations
Singleton
4. codecentric AG
Singleton 01
public class Singleton01 {
// TODO Make this class final?
private static Singleton01 instance = null;
private Singleton01() {
// Private constructor prevents instantiation,
// but also prevents sub-classing.
}
public static Singleton01 getInstance() {
if (instance == null) {
instance = new Singleton01();
}
return instance;
}
}
5. codecentric AG
Singleton 02
private static Singleton02 instance = null;
public static Singleton02 getInstance() {
if (instance == null) {
simulateMultiThreadEnvironment();
instance = new Singleton02();
}
return instance;
}
// Not synchronized, not thread safe.
6. codecentric AG
Singleton 03
private static Singleton03 instance = null;
public synchronized static Singleton03 getInstance() {
if (instance == null) {
simulateMultiThreadEnvironment();
instance = new Singleton03();
}
return instance;
}
// Synchronized, thread safe.
7. codecentric AG
Singleton 04
private static Singleton04 instance = null;
public static Singleton04 getInstance() {
if (instance == null) {
synchronized (Singleton04.class) {
simulateMultiThreadEnvironment();
instance = new Singleton04();
}
}
return instance;
}
// Synchronized, performance optimization, not thread safe.
8. codecentric AG
Singleton 05
private static Singleton05 instance = null;
public static Singleton05 getInstance() {
if (instance == null) {
synchronized (Singleton05.class) {
if (instance == null) {
instance = new Singleton05();
}
}
}
return instance;
}
// Double-checked locking – doesn’t work prior to Java 1.5.
9. codecentric AG
Singleton 06
private static final Singleton06 INSTANCE = new Singleton06();
public static Singleton06 getInstance() {
return INSTANCE;
}
// Eager instantiating of the class. This works.
// What about serialization/deserialization?
10. codecentric AG
Singleton 06 Serializable
public class Singleton06 implements Serializable {
private static final Singleton06 INSTANCE = new Singleton06();
public static Singleton06 getInstance() {
return INSTANCE;
}
}
protected Object readResolve() {
return getInstance();
}
11. codecentric AG
Singleton 07
public enum Singleton07 {
INSTANCE;
}
// What about serialization/deserialization?
// What about reflection?
12. codecentric AG
What is DI / IoC?
Implementation example
No third party library
Dependency Injection / Inversion of Control
13. codecentric AG
Dependency Injection / Inversion of Control
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}
// @Component is used to mark a class – a thing to inject.
// @Inject is used to mark a field – a place to inject.
14. codecentric AG
Dependency Injection / Inversion of Control
@Component
public class Controller {
@Inject
private ManageCapable manager;
…
}
@Component
public class Manager implements ManageCapable {
@Inject
private Repository repository;
…
}
15. codecentric AG
Dependency Injection / Inversion of Control
@Component
public class Repository {
public Resourcable save(Resourcable aResource) {
// Here we "persist" the given resource
// and return it like we really did it.
return aResource;
}
}
16. codecentric AG
Dependency Injection / Inversion of Control
public class PackageScanner {
…
}
public class ClassScanner {
…
}
public class DependencyInjectionManager {
…
}
// https://github.com/dzamurovic/meetup_singleton.git
17. codecentric AG
Dependency Injection / Inversion of Control
public synchronized void run() throws Exception {
if (initialized) {
return;
}
// Find classes annotated with @Component.
List<Class> components = packageScanner.findAnnotatedClasses(
"rs.codecentric.meetup.diioc.example", Component.class);
// For each component...
for (Class component : components) {
Class definingClass = classScanner.getDefiningClass(component);
// ... check if its instance already exists...
if (!graph.containsKey(definingClass)) {
// ... and instantiate it, if it doesn't.
String className = component.getName();
graph.put(definingClass, Class.forName(component.getName()).newInstance());
}
}
}
18. codecentric AG
Dependency Injection / Inversion of Control
// For each object that is created...
for (Iterator<Class> classIterator = graph.keySet().iterator();
classIterator.hasNext();) {
Class definingClass = classIterator.next();
Object object = graph.get(definingClass);
// ... find dependencies it needs, ...
for (Field f : classScanner.findAnnotatedFields(object.getClass(),
Inject.class)) {
if (!graph.containsKey(f.getType())) {
// ... throw an error if a dependency cannot be satisfied, ...
}
// ... or set a value of the dependency.
Object dependency = graph.get(f.getType());
f.set(object, dependency);
}
}
initialized = true;
}
19. codecentric AG
Dependency Injection / Inversion of Control
public static void main(String args[]) throws Exception {
final DependencyInjectionManager diManager =
DependencyInjectionManager.getInstance();
Thread t1 = new DependencyInjectionThread("DI-thread-0", diManager);
Thread t2 = …
t1.start();
t2.st…
t1.join();
t2.j…
diManager.describeDependencyGraph();
}
1. Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
2. The code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization.
3. Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock.If B uses the object before all of the initialization done by A is seen by B the program will likely crash.