单例模式:
volatile /ˈvɒlətaɪl/ 不稳定的;Java中的一个关键字,主要用于修饰变量。其主要作用是保证变量的可见性和有序性。
单例模式有两种模式,懒汉模式和饿汉模式。一个类private修饰其构造方法使其无法对外new出来。
饿汉模式先声明一个static finaly的变量并在class内部new好一个对象。public对外获取变量的方法。
public class Singleton{private static final instance = new Singleton();private Singleton() {// 私有构造方法}public static Singleton getInstance() {return instance;}
}
而懒汉模式在声明static finaly变量时为null,在public对外获取变量的方法内加入判断,判断当前变量是否为空,只有为空才new一个对象出来,否则就直接return 变量;
class Singleton{private static final Singleton singleton = null;private Singleton(){}public Singleton getSingleton() {if (singleton==null){this.singleton = new Singleton();}return singleton;}}
最优解是DCL模式(doublecheck lock)双重锁检,即声明变量时为 static volatile 【变量】 【变量名称】;对外获得方法内先判断【变量名称】是否为空,再判断synchronized 【当前类.class】,再判断变量名称是否为空,为空则 return new对象
那为什么要用双重锁检和volatile,因为多线程的情况下,会有两个线程同时拿到变量名称为null从而进入锁内,涉及到内存声明时会发生指令重排,1分配对象内存地址,2初始化,3指向内存地址。这三步会变换顺序,1分配到了对象的内存地址,2也拿到地址,直接指向内存地址但是未进行初始化,1直接执行发现变量名称不为空直接返回。volatile的作用就包装变量指令不重排。
在Spring IoC容器中管理的Bean的默认作用域就是单例的
public class Singleton { private static volatile Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }
}
代理模式
Invocation /ˌɪnvəˈkeɪʃn/ 调用 InvocationHandler
Proxy /ˈprɒksi/ 代理
Interceptor/ˌɪntəˈseptə(r)/ 拦截器 methodInterceptor
Enhancer /ɪnˈhɑːnsə(r)/ 增强器
代理模式分为静态代理和动态代理两张模式。
静态代理,一个业务接口用来完成实际的业务,我这个类实现业务接口,即我结婚这个实际业务。代理类也实现业务接口,但是在代理类声明时构造函数需要传入我这个类(被代理的)。在代理类实现我结婚时业务时完成前后增强业务。
// 代理类,也实现了UserService接口
public class UserServiceProxy implements UserService { private UserService userService; public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public void addUser(String username, String password) { // 在调用目标方法前添加一些逻辑 System.out.println("UserServiceProxy: before addUser"); // 调用目标对象的方法 userService.addUser(username, password); // 在调用目标方法后添加一些逻辑 System.out.println("UserServiceProxy: after addUser"); } }
动态代理-jdk动态代理,被代理对象与业务接口不变,实际代理对象需要实现invocationHandler接口,重写invoke在此完成前后增强业务。调用时,需要利用Proxy反射proxy.newProxyInstance来获取当前被代理的对象,传递参数是三个当前被代理对象的classLoad(),interfaces(),还有一个就是传入当前被代理对象UserServiceImpl。
接口
// 定义接口
interface UserService {void addUser(String username);
}
实现
// 实现接口的具体类
class UserServiceImpl implements UserService {public void addUser(String username) {System.out.println("添加用户:" + username);}
}
实现invoctionHandler接口
// 实现InvocationHandler接口
class MyInvocationHandler implements InvocationHandler {// 声明一个私有变量private Object target;// 构造函数public MyInvocationHandler(Object target) {this.target = target;}// 实现InvocationHandler接口的invoke方法,该方法在代理对象调用方法时被触发。public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态代理前置操作");Object result = method.invoke(target, args);System.out.println("动态代理后置操作");return result;}
}
代理实现
public class DynamicProxyExample {public static void main(String[] args) {// 创建目标对象UserService userService = new UserServiceImpl();// 创建InvocationHandler实例MyInvocationHandler handler = new MyInvocationHandler(userService);// 创建动态代理对象UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),handler);// 通过代理对象调用方法proxy.addUser("Alice");}
}
动态代理-cglib代理,需要实现methodInterceptor接口,重写intercept方法在此完成增强业务。调用时用enhancer。但是不能代理final类,因为cglib是动态创建子类进行代理,final没有子类。这两种动态代理模式也是AOP的原理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class CglibProxyExample implements MethodInterceptor { private Object target; public CglibProxyExample(Object target) { this.target = target; } public Object getInstance() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable { System.out.println("Before method " + method.getName()); // 调用父类的方法,即被代理类的方法 Object result = proxy.invokeSuper(obj, args); System.out.println("After method " + method.getName()); return result; } public static void main(String[] args) { // 假设MyServiceImpl是MyService的一个实现类 MyService myService = new MyServiceImpl(); CglibProxyExample proxy = new CglibProxyExample(myService); MyService proxyInstance = (MyService) proxy.getInstance(); proxyInstance.doSomething(); // 调用代理对象的方法,会触发intercept方法 }
}
工程模式
简单工厂:一个业务接口,两个实现类。一个工具类,工具类实现对外获取实现类方法。但是需要根据传递参数来返回某一个实现类。接口 = 工具类.获取实现类方法(传递参数)
工厂模式:对工具类的优化,简单工厂的工具类抽象为一个工厂接口。两个类别的实现类,就分别实现工厂接口返回对应产品。只需知道什么类型就使用对应的实现工厂生产商品。
抽象工厂:生产电脑业务接口,对应两个实现类。生产操作系统业务接口,对应两个实现类。生产工厂业务接口内有两个方法一个是实现生产系统,一个是生产电脑,两个实现类。工厂实现类,实现对生产什么电脑的实现,生产什么操作系统的实现。这样在声明什么生产工厂的时候就已经能确定生产什么电脑和操作系统了。始于简单工厂,工厂模式是对简单工厂模式的纵向优化,
抽象工厂是对简单工厂的横向优化
// 抽象产品 A
interface ProductA { void use();
} // 具体产品 A1
class ProductA1 implements ProductA { @Override public void use() { System.out.println("Using Product A1"); }
} // 具体产品 A2
class ProductA2 implements ProductA { @Override public void use() { System.out.println("Using Product A2"); }
} // 抽象产品 B
interface ProductB { void use();
} // 具体产品 B1
class ProductB1 implements ProductB { @Override public void use() { System.out.println("Using Product B1"); }
} // 具体产品 B2
class ProductB2 implements ProductB { @Override public void use() { System.out.println("Using Product B2"); }
} // 抽象工厂
interface AbstractFactory { ProductA createProductA(); ProductB createProductB();
} // 具体工厂 1
class Factory1 implements AbstractFactory { @Override public ProductA createProductA() { return new ProductA1(); } @Override public ProductB createProductB() { return new ProductB1(); }
} // 具体工厂 2
class Factory2 implements AbstractFactory { @Override public ProductA createProductA() { return new ProductA2(); } @Override public ProductB createProductB() { return new ProductB2(); }
} // 客户端代码
public class AbstractFactoryDemo { public static void main(String[] args) { // 使用工厂 1 创建产品族 AbstractFactory factory1 = new Factory1(); ProductA product