代理模式:
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
Java动态代理:在程序运行时,运用反射机制动态创建而成。
本文主要介绍JDK和CGLib动态代理
首先我们了解一下JDK动态代理和CGLib动态代理的主要区别:
JDK动态代理只能为接口创建实例,而CGlib可以为未实现任何接口的类创建代理(为类创建一个子类作为代理类)
在动态代理的性能方面:CGlib创建对象的性能大概是JDK所创建的代理对象的10倍,但是在代理类的创建时间上JDK确是CGlib的8倍左右,如果需要平凡创建代理对象则使用JDK较好,如果是singleton的代理对象则使用CGlib较好。
动态代理在现实中的运用:比较为人熟知的就是Spring的Aop实现
下面首先看看JDK的动态代理实现(注意一定要实现某个接口)
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaDynamic {
public static interface IPerson {
public void eat();
}
public static class PersonImpl implements IPerson {
@Override
public void eat() {
System.out.println("我要满汉全席...");
}
}
public static class PersonEatHandle implements InvocationHandler {
private Object target;
public PersonEatHandle(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
eatbefore();
Object obj = method.invoke(target, args);// 反射调用
eatafter();
return obj;
}
public void eatbefore() {
System.out.println("请点单");
}
public void eatafter() {
System.out.println("请买单");
}
}
public static void main(String[] args) {
// 希望被代理的目标类
IPerson impl = new PersonImpl();
// 将目标类与要植入的代码编织到一起
PersonEatHandle handle = new PersonEatHandle(impl);
// 创建代理类实例
IPerson service = (IPerson)Proxy.newProxyInstance(impl.getClass()
.getClassLoader(), impl.getClass().getInterfaces(), handle);
service.eat();
}
}
在上例中我们在人吃饭之前后分别织入了"点单"和"买单"的逻辑,看看运行结果
下面我们使用CGlib做一个例子:
package test;
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 CGLibDynamic {
public static class Person{
public void eat() {
System.out.println("我要满汉全席...");
}
}
static class CGLibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] param,
MethodProxy proxy) throws Throwable {
eatbefore();
Object object = proxy.invokeSuper(obj, param);
eatafter();
return object;
}
public void eatbefore() {
System.out.println("请点单");
}
public void eatafter() {
System.out.println("请买单");
}
}
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Person person = (Person)proxy.getProxy(Person.class);
person.eat();
}
}
这个例子中Person类没有实现任何接口,同样的我们织入了"点单"和"买单"的逻辑,运行结果和上面例子的运行结果是一样的