代理模式

代理模式(Proxy):对其他对象提供一种代理以控制对这个对象的访问

一、静态代理:代理和被代理对象在代理之前是确定的,它们都是实现了相同的接口或者继承了相同抽象类。

1.首先定义一个呗代理对象和被代理对象实现的接口GiveGift
package com.design.proxy;

/**

  • 礼物

  • @author Administrator

*/

public interface GiveGift {

//送花

public void Flowers();

}
2.创建人物实体Goddess
package com.design.proxy;

/**

  • 女神
  • @author Administrator

*/
public class Goddess {

private String name;

public String getName() {
	return name;
}

public void setName(String name) {
	this.name = name;
}

}
3.创建被代理对象实现GiveGift接口
package com.design.proxy;

import java.util.Random;
/**

  • 追求者
  • @author Administrator

*/
public class Pursuit implements GiveGift {

private Goddess mm;

public Pursuit(Goddess mm){
	this.mm = mm;
}

@Override
public void Flowers() {
	try {
		Thread.sleep(new Random().nextInt(1000));
		System.out.println(mm.getName() + "送你鲜花");
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

}
4.创建代理对象实现GiveGift接口
package com.design.proxy;

/**

  • 代理
  • @author Administrator

*/
public class Proxy implements GiveGift {

public Proxy(Goddess mm) {
	gg = new Pursuit(mm);
}
private Pursuit gg;

@Override
public void Flowers() {
	gg.Flowers();
}

}
5.测试类
package com.design.proxy;

public class Test {

public static void main(String[] args) {
	Goddess mm = new Goddess();
	mm.setName("Jane");
	
	new Proxy(mm).Flowers();;
}

}
测试结果:Jane送你鲜花

二、动态代理
所谓Dynamic Proxy是这样一个class:它是在运行时生成class,该class需要实现一组interface,使用动态代理时必须实现InvocationHandler接口
Ⅰ. JDK动态代理

image.png

Java动态代理类位于java.lang.reflect包下,一般主要涉及两个类:
(1)Interface InvocationHandler:该接口定义一个方法
public object invoke(Object obj, Method method, Object[] args)
在实际应用时,第一个参数obj一般为代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2) Proxy:该类即为动态代理类
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h): 返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明过的方法)

JDK动态代理Demo:
1.创建一个TimeHandler类实现InvocationHandler接口
package com.design.jdkproxy;

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

public class TimeHandler implements InvocationHandler {

public TimeHandler(Object target){
	super();
	this.target = target;
}
private Object target;

/**
 * 参数:
 * proxy 被代理的对象
 * method 被代理对象的方法
 * args 方法的参数
 * 
 * 返回值:
 * Object 方法的返回值
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
		throws Throwable {
	long starttime = System.currentTimeMillis();
	System.out.println("委托送花开始...");
	method.invoke(target);
	long endtime = System.currentTimeMillis();
	System.out.println("女神收到鲜花... 花费时间:"+(endtime-starttime)+"毫秒~");
	return null;
}

}
2.创建测试类
package com.design.jdkproxy;

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

import com.design.proxy.GiveGift;
import com.design.proxy.Goddess;
import com.design.proxy.Pursuit;

public class Test {

public static void main(String[] args) {
	Goddess mm = new Goddess();
	mm.setName("Jane");
	Pursuit cp = new Pursuit(mm);
	InvocationHandler th = new TimeHandler(cp);
	Class<?> cls = cp.getClass();
	ClassLoader loader = cls.getClassLoader();
	Class<?>[] interfaces = cls.getInterfaces();
	/**
	 * loader 类加载器
	 * interfaces 实现接口
	 * h InvocationHandler
	 */
	GiveGift m = (GiveGift)Proxy.newProxyInstance(loader, interfaces, th);
	m.Flowers();
}

}

测试结果:
委托送花开始...
Jane送你鲜花
女神收到鲜花... 花费时间:825毫秒~
JDK动态代理总结:
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法。
2.创建被代理类以及接口。
3.调用Proxy的静态方法,创建一个代理类 newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)。
4.通过代理调用方法。

Ⅱ.CGLIB动态代理(需要cglib-node.jar包)
链接:http://pan.baidu.com/s/1b27bae 密码:sfza
1.创建一个FlowerExecute类
package com.design.cglibproxy;

public class FlowerExecute {

public void Flower(){
	System.out.println("鲜花派送中...");
}

}

2.创建CglibProxy代理类实现MethodInterceptor接口
package com.design.cglibproxy;

import java.lang.reflect.Method;

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

public class CglibProxy implements MethodInterceptor {

private Enhancer enhancer = new Enhancer();

/**
 * 动态创建给定类型的子类
 * 
 * @param clazz 要代理的原始对象
 * @return
 */
public Object getProxy(Class clazz) {
	//设置创建子类的类
	enhancer.setSuperclass(clazz);//设置代理目标
	enhancer.setCallback(this);	//设置回调
	
	return enhancer.create();
}

/**
 * 拦截所有目标类方法的调用
 * 
 * 参数:
 * obj 目标类的实例
 * m 目标反射的方法对象
 * args 方法的参数
 * proxy 代理类的实例
 */
@Override
public Object intercept(Object obj, Method m, Object[] args,
		MethodProxy proxy) throws Throwable {
	System.out.println("前置代理");
	//代理类调用父类的方法
	proxy.invokeSuper(obj, args);
	System.out.println("后置代理");
	
	return null;
}

}
3.测试
package com.design.cglibproxy;

public class Test {

public static void main(String[] args) {
	CglibProxy cp = new CglibProxy();
	
	FlowerExecute fe = (FlowerExecute)cp.getProxy(FlowerExecute.class);
	fe.Flower();
}

}
4.测试结果:
前置代理
鲜花派送中...
后置代理
Ⅲ.综合JDK动态代理与CGLIB动态代理可以发现
JDK动态代理:
1.只能代理实现了接口的类
2.没有实现接口的类不能实现JDK的动态代理
CGLIB动态代理:
1.针对类来实现代理的
2.对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

posted @ 2017-11-21 14:57  FateForever  阅读(159)  评论(0)    收藏  举报