代理:我的理解是目标对象不直接参与目标事件,而是将自己的引用交由代理对象,由代理对象去办目标事件,代理对象可以在做目标事件之前或者之后,可以做一些次要的事,使目标事物更加圆满。
以卖书为例,我们知道印刷厂卖书,一些书店也卖书,对于我们这种消费者来说主要是通过书店卖书,书店会提供打折或者积分的销售方式。
目标对象:印刷厂
代理对象:书店
目标卖书:卖书
次要事件:打折 积分
静态代理 :
//卖书的接口
public interface Subject {
public void sellBook();
}
//目标类 也就是印刷厂
public class RealSubject implements Subject {
@Override
public void sellBook() {
System.out.println("卖书");
}
}
代理类,代理类中有目标类的引用
public class ProxyClazz implements Subject {
private RealSubject realSubject;
public void setRealSubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void sellBook() {
daZhe();
realSubject.sellBook();
jiFen();
}
//打折
private void daZhe() {
System.out.println("打折");
}
//积分
private void jiFen() {
System.out.println("积分");
}
}
客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxyClazz proxy = new ProxyClazz();
proxy.setRealSubject(realSubject);
proxy.sellBook();
}
}
结果:
打折
卖书
积分
jdk动态代理:
还是以卖书为例。
看一下InvovationHandler的说明:
InvocationHandler
是代理实例的调用处理程序 实现的接口。
每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke
方法。
定义一个指派方法调用的调用处理程序:
public class MyInvocationHandler implements InvocationHandler {
private RealSubject realSubject;
public void setRealSubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
//proxy - 在其上调用方法的代理实例
//method - 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在
//其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
//args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
//基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
this.daZhe();
//真是对象执行目标方法
result = method.invoke(realSubject, args);
this.jiFen();
return result;
}
//打折
private void daZhe() {
System.out.println("打折");
}
//积分
private void jiFen() {
System.out.println("积分");
}
}
client端:
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyInvocationHandler handler = new MyInvocationHandler();
handler.setRealSubject(realSubject);
//用过Proxy类得到代理对象
//第一个参数指定代理类的类加载器
//第二个参数是代理类与目标类实现的同一个接口列表
//第三个参数指派方法调用的调用处理程序
Subject proxySubject = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), RealSubject.class.getInterfaces(), handler);
proxySubject.sellBook();
}
}
结果:
打折
卖书
积分
这里说一下jdk动态代理的缺点,代理类和目标类必须实现同一接口,在代理对象调用目标方法时,会被拦截执行调用处理程序,也就是说没有实现接口的类不能被代理。
Cglib动态代理
Cgilib也是一种代理模式,与jdk代理最大的不同就是,目标类不需要继承接口也可以被代理。
public class RealSubject {
public void sellBook() {
System.out.println("卖书");
}
}
public class MyMethodInterceptor implements MethodInterceptor {
//Object 代理对象
//Method 被代理对象方法
//args 方法入参
//methodProxy 代理方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
daZhe();
methodProxy.invokeSuper(obj, args);
jiFen();
return null;
}
//打折
private void daZhe() {
System.out.println("打折");
}
//积分
private void jiFen() {
System.out.println("积分");
}
}
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new MyMethodInterceptor());
RealSubject proxy = (RealSubject)enhancer.create();
proxy.sellBook();
}
}
打折
卖书
积分
cglib是动态的生成目标类的子类作为代理类。子类重写父类的非final方法,完成对方法的代理。