单例模式

为什么要用单例模式: 保证一个类在程序中的唯一性

如何保证唯一性?

1,不允许其他程序用new创建该类对象。(私有化构造方法)

2,在该类创建一个本类实例。(定义一个私有化的静态成员)

3,对外提供一个方法让其他程序可以获取该对象。(定义一个获取实例的静态方法)

有哪些实现单例模式的方式?

懒汉式(注意: 该实现方式在多线程下存在安全隐患)

  1. /**
  2. * 单例模式 -- 懒汉式, 会存在多线程安全隐患
  3. * 类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象。
  4. * 延迟加载形式。
  5. */
  6. public class LazySingle {
  7. private static LazySingle single;
  8. private LazySingle() {}
  9. public static LazySingle getInstance() {
  10. if(single == null) { // 多加一次, 解决效率问题
  11. // 多线程下存在安全隐患, 需同步
  12. synchronized (LazySingle.class) {
  13. if(single == null) {
  14. single = new LazySingle();
  15. }
  16. }
  17. }
  18. return single;
  19. }
  20. }

饿汉式

  1. /**
  2. * 单例模式 -- 饿汉式
  3. * 类一加载,对象就已经存在了。
  4. */
  5. public class HungerSingle {
  6. static HungerSingle single = new HungerSingle();
  7. private HungerSingle() {}
  8. public static HungerSingle getInstance() {
  9. return single;
  10. }
  11. }

代理模式

定义: 给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介

为什么要用代理模式?

中介隔离作用:

在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

开闭原则,增加功能:

代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

有哪几种实现代理模式的方式?

静态代理

  1. package com.lius.javase.demo.proxy.staticProxy;
  2. /**
  3. * 静态代理
  4. *
  5. * 第一步: 创建服务类接口
  6. * 第二步: 实现服务接口
  7. * 第三步:创建代理类
  8. * 第四步:编写测试类
  9. *
  10. * 总结:
  11. * 优点: 可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
  12. * 缺点: 我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
  13. */
  14. public class staticProxy {
  15. interface BuyHouseService {
  16. void bugHouse();
  17. }
  18. static class BuyHouseServiceImpl implements BuyHouseService {
  19. @Override
  20. public void bugHouse() {
  21. System.out.println("我要买房");
  22. }
  23. }
  24. static class BuyHouseProxy implements BuyHouseService{
  25. private BuyHouseService buyHouseService;
  26. public BuyHouseProxy(final BuyHouseService buyHouseService) {
  27. this.buyHouseService = buyHouseService;
  28. }
  29. @Override
  30. public void bugHouse() {
  31. System.out.println("买房前准备");
  32. buyHouseService.bugHouse();
  33. System.out.println("买房后装修");
  34. }
  35. }
  36. static class test {
  37. public static void main(String[] args) {
  38. BuyHouseServiceImpl buyHouse = new BuyHouseServiceImpl();
  39. buyHouse.bugHouse();
  40. BuyHouseProxy proxy = new BuyHouseProxy(buyHouse);
  41. proxy.bugHouse();
  42. /**
  43. * 输出结果
  44. * 我要买房
  45. * 买房前准备
  46. * 我要买房
  47. * 买房后装修
  48. */
  49. }
  50. }
  51. }

动态代理

  1. package com.lius.javase.demo.proxy.dynamicProxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. /**
  6. * 动态代理
  7. *
  8. * 总结:
  9. * 虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。
  10. * 但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。
  11. * 回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。
  12. * Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。
  13. * 有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。
  14. * 接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。
  15. * 如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。
  16. * 此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。
  17. * 但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。
  18. */
  19. public class DynamicProxy {
  20. interface BuyHouseService {
  21. void buyHouse();
  22. }
  23. static class BuyHouseServiceImpl implements BuyHouseService {
  24. @Override
  25. public void buyHouse() {
  26. System.out.println("我要买房");
  27. }
  28. }
  29. static class DynamicProxyHandler implements InvocationHandler {
  30. private Object object;
  31. public DynamicProxyHandler(final Object object) {
  32. this.object = object;
  33. }
  34. @Override
  35. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  36. System.out.println("xxx前准备");
  37. Object result = method.invoke(object, args);
  38. System.out.println("xxx后xxx");
  39. return result;
  40. }
  41. }
  42. static class test {
  43. public static void main(String[] args) {
  44. BuyHouseServiceImpl buyHouse = new BuyHouseServiceImpl(); // 实现类
  45. /**
  46. * 注意Proxy.newProxyInstance()方法接受三个参数:
  47. *
  48. * ClassLoader loader: 指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  49. * Class<?>[] interfaces: 指定目标对象实现的接口的类型,使用泛型方式确认类型
  50. * InvocationHandler: 指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
  51. */
  52. BuyHouseService proxyBuyHouse = (BuyHouseService) Proxy.newProxyInstance(
  53. BuyHouseServiceImpl.class.getClassLoader(),
  54. new Class[]{BuyHouseService.class},
  55. new DynamicProxyHandler(buyHouse));
  56. proxyBuyHouse.buyHouse();
  57. /**
  58. * 输出结果:
  59. * xxx前准备
  60. * 我要买房
  61. * xxx后xxx
  62. */
  63. }
  64. }
  65. }

CGLIB代理

  1. package com.lius.javase.demo.proxy.cglibProxy;
  2. import net.sf.cglib.proxy.Enhancer;
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5. import java.lang.reflect.Method;
  6. /**
  7. * 依赖:
  8. * <dependency>
  9. * <groupId>cglib</groupId>
  10. * <artifactId>cglib</artifactId>
  11. * <version>2.2.2</version>
  12. * </dependency>
  13. */
  14. /**
  15. * CGLib代理
  16. * 使用场景:
  17. * JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。
  18. * CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,
  19. * 并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
  20. * 但因为采用的是继承,所以不能对final修饰的类进行代理。
  21. * JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
  22. */
  23. public class CGLibProxy {
  24. static class BuyHouse {
  25. public void buyHouse() {
  26. System.out.println("我要买房");
  27. }
  28. }
  29. static class CgLibProxy implements MethodInterceptor {
  30. /**
  31. * @param clazz 被代理的类
  32. */
  33. public Object getInstance(Class clazz) {
  34. // 1. 创建字节码增强器,用来对被代理的类扩展。
  35. Enhancer enhancer = new Enhancer();
  36. // 2. 告诉cglib,生成的子类需要继承那个父类。
  37. enhancer.setSuperclass(clazz);
  38. // 3. 设置回调
  39. enhancer.setCallback(this);
  40. // 4. 生成源代码,编译成class文件,加载到jvm,并返回代理对象。
  41. Object obj = enhancer.create();
  42. return obj;
  43. }
  44. /**
  45. * @param obj 生成的子类
  46. * @param method 被拦截的方法
  47. * @param args 被拦截方法的参数
  48. * @param proxy 触发父类的方法对象
  49. */
  50. @Override
  51. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  52. System.out.println("xxx前准备");
  53. proxy.invokeSuper(obj, args);
  54. System.out.println("xxx后xxx");
  55. return null;
  56. }
  57. }
  58. static class Test {
  59. public static void main(String[] args) {
  60. BuyHouse buyHouse = new BuyHouse();
  61. CgLibProxy cgLibProxy = new CgLibProxy();
  62. BuyHouse buyHouseProxy = (BuyHouse) cgLibProxy.getInstance(buyHouse.getClass());
  63. buyHouseProxy.buyHouse();
  64. /**
  65. * 输出结果:
  66. * xxx前准备
  67. * 我要买房
  68. * xxx后xxx
  69. */
  70. }
  71. }
  72. }