一、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 @ 2018-04-18 22:57  IT云私塾  阅读(204)  评论(0编辑  收藏  举报