代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。举例说明,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
比较典型的例子,就像生活中的大明星,他们拥有自己的经纪人,那么一般很多事就由经纪人代替他们自己来进行。比如接一部电视剧
1、静态代理
首先,我们需要定义接受剧组邀请的接口:
/**
* 接受邀请拍戏
*
* @author admin
* @version V1.0
* @email ${EMAIL}
* @since 2017-11-27 20:25
*/
public interface AcceptingInvitation {
void Filming();
}
public class Mingxing implements AcceptingInvitation{
@Override
public void Filming() {
System.out.println("演戏!");
}
}
经纪人类代理明星处理事情:
public class Agent implements AcceptingInvitation{
private Mingxing mingxing;
public Agent(Mingxing mingxing){
this.mingxing = mingxing;
}
@Override
public void Filming() {
mingxing.Filming();
}
}
验证:
public class WuDongQianKun {
public static void main(String[] args) {
Mingxing mingxing = new Mingxing();
//经纪人代理明星接戏
Agent agent = new Agent(mingxing);
//实际演戏的是明星
agent.Filming();
}
}
结果:
以上过程为静态代理的方式。
2、动态代理
在以上基础上,我们看看动态代理如何实现。
首先是基于JDK的动态代理:
创建代理类实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler{
// 被代理类的实例
Object object;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object object){
this.object = object;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.object, args);
/*
* after : doSomething();
*/
return result;
}
}
验证该动态代理方式:
public class DouPoCangQiong {
public static void main(String[] args) {
//我们要代理的真实对象
Mingxing mingxing = new Mingxing();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(mingxing);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数customer.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
AcceptingInvitation ai =(AcceptingInvitation) Proxy.newProxyInstance(handler.getClass()
.getClassLoader(),mingxing.getClass().getInterfaces(),handler);
ai.Filming();
}
}
结果:
JDK动态代理的具体步骤如下:
1、创建一个类,实现invocationHandler接口,重写invoke()方法。
2、创建被代理的类和接口。
3、调用Proxy的静态方法,实例化一个代理类。
4、通过该代理类调用方法。
然后是基于cglib的动态代理实现:
创建一个类实现Spring的cglib中的MethodInterceptor方法
public class CglibProxy implements MethodInterceptor{
//创建Enhancer对象为非接口类型创建一个Java代理,Enhancer动态创建了给定类型的子类但是拦截了所有的方法。
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* 参数:
* obj目标实例对象
*method 目标方法的反射对象
* args方法的参数
* proxy代理类的实例
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
methodProxy.invokeSuper(o,objects);
return null;
}
}
public class DaZhuZai {
public static void main(String[] args) {
//创建动态代理实例
CglibProxy cglibProxy = new CglibProxy();
//通过代理实例对Mingxing类进行动态代理
Mingxing mingxing = (Mingxing)cglibProxy.getProxy(Mingxing.class);
mingxing.Filming();
}
}
结果:
cglib实现动态代理的过程:
1、导入spring包。
2、创建代理类实现Spring cglib包中的MethodInterceptor 接口,重写intercept方法。
3、创建被代理对象和接口。
4、实例化代理类。
5、调用方法
动态代理的好处:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理。Proxy 很美很强大,但是仅支持 interface 代理。Java 的单继承机制注定了这些动态代理类们无法实现对 class 的动态代理。好在有cglib为Proxy提供了弥补。class与interface的区别本来就模糊,在java8中更是增加了一些新特性,使得interface越来越接近class,当有一日,java突破了单继承的限制,动态代理将会更加强大。