一、spring的成长之路——代理设计模式

java常用的设计模式详解:

1.代理模式(JDK的动态代理)

【IDept.java】

​ 这是一个简单的就接口,进行数据的更新

package com.itcloud.pattern.proxy;

public interface IDept {
    void update();
}

【DeptImp.java】

​ Dept的实现类

package com.itcloud.pattern.proxy;

public class DeptImpl implements IDept {
    @Override
    public void update() {
        System.out.println("完成核心功能,进行数据的更新操作");
    }
}

【InvoProxy.java】

​ 代理类,被代理对象只需要完成核心功能,而其他的功能都由代理对象完成

package com.itcloud.pattern.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InvoProxy implements InvocationHandler {

    private Object obj;

    // 首先要获取代理对象

    public Object getProxyInterface(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    /**
      实现的基本步骤
      1.获取代理类对象,然后获取其接口
      2.生成新的类,实现代理类的接口,这个类其实只是字节码文件
      3.在新生成的类中进行代码的执行
     */
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("数据库开启事物");// 这些事情由代理类完成     
        try {
            return method.invoke(this.obj, args); // 代理类完成核心功能
        } catch (Exception e) {

        } finally {
            System.out.println("进行事物的回滚操作");
        }
        return null;
    }
}

【TestDemo.java】

public class TestDemo {
    public static void main(String[] args) {
        IDept dept = (IDept)new InvoProxy().getProxyInterface(new DeptImpl());
        dept.update();
    }
}
//测试结果
/*
    数据库开启事物
    完成核心功能,进行数据的更新操作
    进行事物的回滚操作
*/

在代码中我们说过,代理对象会生成一个代理类,那么我们来看一下这个类究竟长什么样

首先在测试类中将字节码写入本地文件

【TestDemo.java】

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

public class TestDemo {
    public static void main(String[] args) throws Exception {
        IDept dept = (IDept)new InvoProxy().getProxyInterface(new DeptImpl());
        dept.update();
        byte[] $Proxy0 = ProxyGenerator.generateProxyClass("$Proxy0", new Class<?>[]{IDept.class});
        FileOutputStream out = new FileOutputStream("G:\\$Proxy0.class");
        out.write($Proxy0);
        out.close();
    }
}

我们可以在g盘中生成一个$Proxy0.class文件,这个文件就是类的字节码文件,你看不懂我也看不懂这时候需要借用反编译软件(jd-gui-0.3.6),进行反编译

【$Proxy0.class】

import com.itcloud.pattern.proxy.IDept;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
  extends Proxy
  implements IDept
{
  private static Method m1;
  private static Method m2;
  private static Method m0;
  private static Method m3;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final Boolean update()
    throws 
  {
    try
    {
      return (Boolean)this.h.invoke(this, m3, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m3 = Class.forName("com.itcloud.pattern.proxy.IDept").getMethod("update", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

总结:jdk动态代理必须要有接口

3.cglib代理

cglib中,被代理对象不需要继承相关接口

【pom.xml】文件中添加依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.4</version>
</dependency>

【Student.java】

package com.itcloud.pattern.cglib;
public class Student {

    public void update() {
        System.out.println("进行数据的更新操作");
    }
}

【CglibProxy.java】

package com.itcloud.pattern.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {

    //获取代理类的对象
    public Object getInstance(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);
        enhancer.setSuperclass(clazz);//设置生成代理类的父类
        //enhancer.create()这个方法会创建com.itcloud.pattern.cglib.Student$$EnhancerByCGLIB$$4c126679@20e2cbe0代理类,这个代理类是被代理类的子类
        return enhancer.create();//enhancer.create() instanceof Student 返回结果true
    }


    /**
     *
     * @param obj cglib生成的代理类
     * @param method 被代理对象中的方法
     * @param args 方法的参数
     * @param methodProxy 代理方法,即生成代理类中的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("数据更新前,事物开启");

        try {
            return methodProxy.invokeSuper(obj, args);//明确调用父类中的方法
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("出现异常,事物回滚,rollback");
        }
        return null;
    }
}

此时我们也可以像JDK动态代理那样对生成的代理类进行字节码反编译。
爱生活爱分享欢迎您的关注与加入自学交流群:461265466这里写图片描述

posted on 2018-04-18 22:57 IT云私塾 阅读() 评论() 编辑 收藏

版权声明:本文为hu1056043921原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hu1056043921/p/8878213.html