比较官方一点解释:为另一对象提供一个替身或者占位符,以控制对这个对象的访问,这句话看起来有一些比较难理解,那么下面我们用几个方便我们理解的场景去理解这句话;
在理解上,我们可以按照上面的示例去理解,但是实际的开发过程中,会多多少少有些出入;但是核心思想基本就是这样了;代码实现,代理对象是持有的目标对象的引用,方法调用是由代理对象发起的,而真正的方法执行还有由目标对象去做的;代理对象只是在方法的前后增强了部分功能;回归的上面的例子;情书或者礼物是你自己准备的,哥们儿只是帮你转交一下,妹子看到的还是你的那份情书;最多的是哥们儿觉得你的礼物包装盒(信封)不好看,帮你重新再弄了一个更好看的盒子(充分);
什么是静态代理
代码实现静态代理
public interface Subject {
public void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("我是 RealSubject");
}
}
public class Proxy implements Subject {
private Subject subject;
// 这里将需要代理的真实对象传递进来
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
// 由于这一趴是自己写的,所以一旦接口增加方法,下面的这些增强的东西都需要再解析
System.out.println("代码执行前增强!");
try {
// 调用真实对象中的方法
subject.request();
System.out.println("代码执行后增强!");
} catch (Exception e) {
System.out.println("代码执行异常!");
// 由于这里只是代理,所以对异常处理完之后,还需要将其再抛出去
throw e;
}
System.out.println("代码执行完!");
}
}
public class test {
public static void main(String[] args) {
Subject subject = new Proxy(new RealSubject());
subject.request();
}
}
优点
缺点
为了解决前面静态代理中出现的大量手动档的重复代码;提高代码的灵活性和可维护性,就出现了一项新的代理方式--动态代理;何为动态代理?简单的理解就是Proxy的这个类不需要我们手动去写了,而是自动生成的!基于这个生成生成,就出现了两种方式:JDK动态代理和Cglib动态代理
特点
UML图
代码实现
public interface Subject {
public void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("我是 RealSubject");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler {
//真实的目标对象
private Object target;
/**
* @param target 真实的目标对象
*/
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstrance() {
// 三个参数
// 第一个:目标对象的类加载器 通过object.getClass().getClassLoader() 获取
// 第二个:目标对象实现的接口
// 第三个:事件处理,执行目标对象的方法时,会触发事件处理器方法(也就是InvocationHandler中的invoke)
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代码执行前增强!");
Object returnObj;
try {
// 执行真实的目标对象的方法
returnObj = method.invoke(target, args);
System.out.println("代码执行后增强!");
} catch (Exception e) {
System.out.println("代码执行异常!");
// 由于这里只是代理,所以对异常处理完之后,还需要将其再抛出去
throw e;
}
System.out.println("代码执行完!");
return returnObj;
}
}
public class test {
public static void main(String[] args) {
// 设置参数,将生成的代理对象以文件的形式输出到com.sun.proxy.$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//生成目标对象
Subject target = new RealSubject();
//通过ProxyFactory生成代理对象
Subject proxyObj = (Subject) new ProxyFactory(target).getProxyInstrance();
//调用方法
proxyObj.request();
}
}
// 开启输出
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
在项目根目录的以下路径
com.sun.proxy.$Proxy0.class
不管是静态代理还是JDK的动态代理,我们都是基于接口实现的代理,但是实际开发过程中,往往也会存在一个单独的类,他并没有实现任何接口,这个时候,我们就可以使用目标对象的子类(抽象类)来实现代理;这种方式我们称之为Cglib代理
特点
测试代码UML
代码实现
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
public class RealSubject {
public void request() {
System.out.println("我是 RealSubject");
}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstrance() {
//实例化Enhancer对象
Enhancer enhancer = new Enhancer();
//设置代理类拦截器 this指当前的Interceptor
enhancer.setCallback(this);
//如果目标对象是普通的类,这里就设置目标的对象为父类
//设置当前的目标类为父类
enhancer.setSuperclass(target.getClass());
//如果目标对象实现了接口,我们要以接口去实现动态代理,就设置下面的接口参数
//设置实现的接口 获取传入进来的对象的接口类
//enhancer.setInterfaces(target.getClass().getInterfaces());
//返回创建的对象
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("代码执行前增强!");
Object returnObj;
try {
// 执行真实的目标对象的方法
returnObj = method.invoke(target, args);
System.out.println("代码执行后增强!");
} catch (Exception e) {
System.out.println("代码执行异常!");
// 由于这里只是代理,所以对异常处理完之后,还需要将其再抛出去
throw e;
}
System.out.println("代码执行完!");
return returnObj;
}
}
public class test {
public static void main(String[] args) {
//将生成的代理对象输出到指定的路径
//E://logs为输出的路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://logs");
//目标对象
RealSubject realSubject = new RealSubject();
//生成代理对象
RealSubject proxyObj = (RealSubject) new ProxyFactory(realSubject).getProxyInstrance();
//调用方法
proxyObj.request();
}
}
由上图可以看出,是生成了一个叫
RealSubject$$EnhancerByCGLIB$$421f0be4
的代理类,他是继承了目标对象RealSubject
,其中核心代码如下:
public class test {
public static void main(String[] args) {
//将生成的代理对象输出到指定的路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://logs");
// 目标对象
Subject realSubject = new RealSubject();
// 代理对象
Subject proxyObj = (Subject) new ProxyFactory(realSubject).getProxyInstrance();
// 方法调用
proxyObj.request();
}
}
类似于JDK动态代理,这里的代理对象和目标对象一样,也实现了相同的接口,核心的代理方法的实现和上面介于抽象类的方式差不多,可以仔细阅读一下生成的代理对象,就可以很轻松的理解其实现逻辑。
这一翻看下来是不是发现,代理模式并没有那么的神秘,但是它真的很重要,实际开发中通过代理去实现,比如以下的一些场景。
所以,理解了代理模式不管是在实际的开发过程中,还是在阅读很多框架的源码,都会起到很大的帮助。