代理模式:就是一个类的功能通过其他类调用实现,这个其他类就是代理。一般的用处就是在执行功能的时候,可以通过代理在功能执行的前后增加其他的功能。
需求场景:用户各种操作的日志的记录
静态代理:
关系图:
代码:
package proxy;
//静态代理
public class StaticProxy {
public static void main(String[] args) {
OperationProxy operationProxy = new OperationProxy();
operationProxy.login();
/**
* 操作之前记录日志
* 晓峰进行了登录
* 操作之后记录日志
*/
}
}
//操作
abstract class Operation {
abstract public void login();
abstract public void logout();
abstract public void order();
}
//真实的操作
class RealOperation extends Operation{
public void login() {
System.out.println("晓峰进行了登录");
}
public void logout() {
System.out.println("晓峰进行了退出");
}
public void order() {
System.out.println("晓峰进行了下单");
}
}
//代理类
class OperationProxy {
RealOperation realOperation;
public OperationProxy() {
this.realOperation = new RealOperation();
}
public void login() {
beforeLog();
realOperation.login();
afterLog();
}
public void logout() {
beforeLog();
realOperation.logout();
afterLog();
}
public void order() {
beforeLog();
realOperation.order();
afterLog();
}
private void beforeLog() {
System.out.println("操作之前记录日志");
}
private void afterLog() {
System.out.println("操作之后记录日志");
}
}
这就是静态代理了,但是静态代理有个问题,就是如果每一个类中的每一个方法 都需要增加若干个相同功能,那岂不是每一个功能都需要设置代理,就像上面的代码,那就要疯掉了,所以需要一个实现一个东西,可以动态的给方法设置代理。动态的获取到执行的方法。这就是动态代理。
动态代理:
package proxy.dynamic;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
//创建被代理的实例对象
Operation realOperation = new RealOperation();
//创建InvocationHandler对象
OperationInvocationHandler operationHandler = new OperationInvocationHandler<Operation>(realOperation);
//创建代理对象,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Operation realOperationProxy = (Operation) Proxy.newProxyInstance(Operation.class.getClassLoader(),new Class<?>[]{Operation.class}, operationHandler);
realOperationProxy.login();
//也可以使用下面的方式创建代理类对象,Proxy.newProxyInstance其实就是对下面代码的封装
/*try {
//使用Proxy类的getProxyClass静态方法生成一个动态代理类renterProxy
Class<?> operationProxyClass = Proxy.getProxyClass(Operation.class.getClassLoader(), new Class<?>[]{Operation.class});
//获取代理类renterProxy的构造器,参数为InvocationHandler
Constructor<?> constructor = operationProxyClass.getConstructor(InvocationHandler.class);
//使用构造器创建一个代理类实例对象
Operation renterProxy = (Operation)constructor.newInstance(operationHandler);
renterProxy.login();
} catch (Exception e) {
e.printStackTrace();
}*/
/**
* 操作之前记录日志
* 晓峰进行了登录
* 操作之后记录日志
*/
}
}
//操作
interface Operation {
public void login();
public void logout();
public void order();
}
//真实的操作
class RealOperation implements Operation {
public void login() {
System.out.println("晓峰进行了登录");
}
public void logout() {
System.out.println("晓峰进行了退出");
}
public void order() {
System.out.println("晓峰进行了下单");
}
}
//代理类
class OperationInvocationHandler<T> implements InvocationHandler {
//被代理类的对象
private T target;
public OperationInvocationHandler(T target){
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//代理过程中插入其他操作
beforeLog();
Object result = method.invoke(target, args);
afterLog();
return result;
}
private void beforeLog() {
System.out.println("操作之前记录日志");
}
private void afterLog() {
System.out.println("操作之后记录日志");
}
}
这就是动态代理了,动态代理任何一个类的方法,当然这种方式有一个缺陷就是类必须需要实现接口,如果没有实现接口就无法用这种方式了(如果没有实现接口可以使用cglib的动态代理方式,原理是创建一个子类(静态代理类),然后创建调用)
原理:创建一个临时的类(这个类其实就是相当于一个静态代理的类),并将这个类放到内存中,通过反射创建对象,进行调用