1、静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
缺点:一旦接口增加方法,目标对象与代理对象都要维护。
1.1、类图结构
1.2、代码实现
Subject.java
package com.design.demo.proxy;
/**
* 抽象接口
* @author administrator
* @date 2020-05-24 23:47
*/
public interface Subject {
/**
* 被代理方法的具体实现
*/
public void doSomething();
}
SubjectImpl.java
package com.design.demo.proxy;
/**
* 抽象接口的实现
* 真实的实现者
*
* @author administrator
* @date 2020-05-24 23:49
*/
public class SubjectImpl implements Subject {
@Override
public void doSomething() {
System.out.println("doSomething...");
}
}
SubjectProxy.java
package com.design.demo.proxy;
/**
* 抽象接口的具体实现
* 代理类,持有真实实现的实例
*
* @author administrator
* @date 2020-05-24 23:49
*/
public class SubjectProxy implements Subject {
private Subject subject;
public SubjectProxy(Subject subject) {
this.subject = subject;
}
@Override
public void doSomething() {
System.out.println("before doSomething...");
subject.doSomething();
System.out.println("after doSomething...");
}
}
ClientTest.java
package com.design.demo.proxy;
/**
* 测试客户类
*
* @author administrator
* @date 2020-05-25 0:04
*/
public class ClientTest {
public static void main(String[] args) {
Subject targetSubject = new SubjectImpl();
Subject proxySubject = new SubjectProxy(targetSubject);
proxySubject.doSomething();
}
}
测试类运行结果
2、动态代理
代理类在程序运行时创建的代理方式被成为动态代理
2.1、JDK动态代理
缺点:目标必须实现接口,不然无法实现动态代理
2.1.1、类图结构
2.1.2、代码实现
Subject.java
package com.design.demo.proxy1;
/**
* 抽象接口
* @author administrator
* @date 2020-05-24 23:47
*/
public interface Subject {
/**
* 被代理方法的具体实现
*/
public void doSomething();
}
SubjectImpl.java
package com.design.demo.proxy1;
/**
* 抽象接口的实现
* 真实的实现者
*
* @author administrator
* @date 2020-05-24 23:49
*/
public class SubjectImpl implements Subject {
@Override
public void doSomething() {
System.out.println("doSomething...");
}
}
InvocationHandlerImpl.java
package com.design.demo.proxy1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 调用处理器实现类
* 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象
*
* @author administrator
* @date 2020-05-25 22:53
*/
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 这个就是我们要代理的真实对象
*/
private Object target;
/**
* 构造方法,给我们要代理的真实对象赋初值
*
* @param target
*/
public InvocationHandlerImpl(Object target) {
this.target = target;
}
/**
* 该方法负责集中处理动态代理类上的所有方法调用。
* 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
*
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("before doSomething...");
System.out.println("Method:" + method);
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object returnValue = method.invoke(target, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after doSomething...");
return returnValue;
}
}
ClientTest.java
package com.design.demo.proxy1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 测试客户类
*
* @author administrator
* @date 2020-05-25 23:01
*/
public class ClientTest {
public static void main(String[] args) {
//代理的真实对象
Subject realSubject = new SubjectImpl();
/**
* InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
* 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
* 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
*/
InvocationHandler handler = new InvocationHandlerImpl(realSubject);
ClassLoader loader = realSubject.getClass().getClassLoader();
Class[] interfaces = realSubject.getClass().getInterfaces();
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
subject.doSomething();
}
}
测试类运行结果
2.2、CGLIB动态代理
上面的静态代理和JDK动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
优点:实现了不适用接口就可以实现动态代理
缺点:也是因为它的优点导致,实现类没有统一的限定格式
2.2.1、类图结构
2.2.2、代码实现
SubjectImpl.java
package com.design.demo.proxy2;
/**
* 真实的实现者,没有实现任何接口
*
* @author administrator
* @date 2020-05-24 23:49
*/
public class SubjectImpl {
public void doSomething() {
System.out.println("doSomething...");
}
}
MyMethodInterceptor.java
package com.design.demo.proxy2;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 方法拦截器
*
* @author administrator
* @date 2020-05-25 23:52
*/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("before doSomething...");
//注意这里的方法调用,不是用反射
Object object = methodProxy.invokeSuper(obj, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after doSomething...");
return object;
}
}
ClientTest.java
package com.design.demo.proxy2;
import com.design.demo.proxy1.SubjectImpl;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
/**
* 测试客户类
*
* @author administrator
* @date 2020-05-27 20:41
*/
public class ClientTest {
public static void main(String[] args) {
//在指定目录下生成动态代理类,有兴趣可以反编译看一下里面到底是一些什么东西
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\1");
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(SubjectImpl.class);
//设置回调函数
enhancer.setCallback(new MyMethodInterceptor());
//这里的creat方法就是正式创建代理类
SubjectImpl subjectProxy = (SubjectImpl) enhancer.create();
//调用代理类的方法
subjectProxy.doSomething();
}
}
测试类运行结果