懒汉模式
package designpattern.lazysingleton;
import lombok.SneakyThrows;
public class LazySingletonTest {
public static void main(String[] args) {
LazySingleton instance = LazySingleton.getInstance();
LazySingleton instance1 = LazySingleton.getInstance();
System.out.println(instance==instance1);
}
class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
@SneakyThrows
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
饿汉模式
package designpattern.hungrysingleton;
import lombok.SneakyThrows;
import java.lang.reflect.Constructor;
public class HungrySingletonTest {
@SneakyThrows
public static void main(String[] args) {
HungrySingleton instance = HungrySingleton.getInstance();
System.out.println(instance);
}
}
class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return instance;
}
}
静态内部类模式:
package designpattern.innerclasssingleton;
import lombok.SneakyThrows;
import java.lang.reflect.Constructor;
public class InnerClassSingletonTest {
@SneakyThrows
public static void main(String[] args) {
System.out.println(InnerClassSingleton.getInstance());
}
}
class InnerClassSingleton{
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
如何防止反射攻击?
不适用于懒汉模式!!!
例如静态内部类模式:
在调用构造器的时候,对其进行判空,并抛出异常,以防止反射攻击
package designpattern.innerclasssingleton;
import lombok.SneakyThrows;
import java.lang.reflect.Constructor;
public class InnerClassSingletonTest {
@SneakyThrows
public static void main(String[] args) {
Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();
System.out.println(innerClassSingleton);
System.out.println(InnerClassSingleton.getInstance());
}
}
class InnerClassSingleton{
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
if(InnerClassHolder.instance != null){
throw new RuntimeException("Singleton mode can't have multiple instances.");
}
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
如何防止反序列化攻击?
同样是用静态内部类模式做演示:
方法是在类中提供一个 readResolve() 方法,代码如下:
package designpattern.innerclasssingleton;
import lombok.SneakyThrows;
import java.io.*;
public class InnerClassSingletonSerializableTest {
@SneakyThrows
public static void main(String[] args) {
InnerClassSingletonSerializable instance = InnerClassSingletonSerializable.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("testSerializable"));
oos.writeObject(instance);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("testSerializable"));
InnerClassSingletonSerializable o = (InnerClassSingletonSerializable) ois.readObject();
System.out.println(instance == o);
}
}
class InnerClassSingletonSerializable implements Serializable {
static final long serialVersionUID = 42L;
private static class InnerClassHolder {
private static InnerClassSingletonSerializable instance = new InnerClassSingletonSerializable();
}
private InnerClassSingletonSerializable() {
if (InnerClassHolder.instance != null) {
throw new RuntimeException("Singleton mode can't have multiple instances.");
}
}
public static InnerClassSingletonSerializable getInstance() {
return InnerClassHolder.instance;
}
private Object readResolve() throws ObjectStreamException {
return InnerClassHolder.instance;
}
}