代理模式就是某一个类需要访问一个目标类,不是通过直接访问的方式,而是先访问一个中间类,再由这个中间类去访问目标类。代理模式一般用于保护目标类,或者增强目标类。
代理模式类图interface是顶层接口,proxy是代理类,Impl是目标类,client通过访问proxy进而访问到真正的Impl。
代理模式的优缺点- 优点
1.代理模式能的能保护目标类的实现细节。
2.增强目标对类,可以不修改目标类的情况下在代理类中添加一些其他实现。
3.降低了目标类和调用类之间的耦合。
- 缺点
1.代理模式会造成系统设计中类的数目的增加。
2.在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
3.增加了系统的复杂度。
- 静态代理
- JDK动态代理
静态代理的目标类和代理类需要实现同一接口。
优点:静态代理可以做到在不修改目标类的前提下,对目标类的功能进行扩展。
缺点:但是这种方式会导致多一些接口,并且接口增加了方法,目标类和代理类都需要修改。
示例代码- 接口
public interface UserService {
void eat();
}
- 目标类
public class UserServiceImpl implements UserService{
@Override
public void eat() {
System.out.println("eat");
}
}
- 代理类
public class ProxyImpl implements UserService{
private UserService userService;
public ProxyImpl(UserService userService) {
this.userService = userService;
}
@Override
public void eat() {
System.out.println("吃饭之前");
userService.eat();
System.out.println("吃饭之后");
}
}
- 调用者
public class Demo {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ProxyImpl proxyImpl = new ProxyImpl(userService);
proxyImpl.eat();
}
}
JDK动态代理
动态代理
在java的java.lang.reflect包下面有一个InvocationHandler接口和动态代理类Proxy,用来实现jdk的动态代理。
示例代码- 接口
public interface UserService {
void sleep();
void eat();
}
- 实现类
public class UserServiceImpl implements UserService {
@Override
public void sleep() {
System.out.println("sleep");
}
@Override
public void eat() {
System.out.println("eat");
}
}
- 处理器类
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法"+ method.getName() +"调用前");
Object returnValue = method.invoke(target, args);
System.out.println("方法"+ method.getName() +"调用后");
return returnValue;
}
}
- 调用者
public class Demo {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new InvocationHandlerImpl(userService);
UserService userService1 = (UserService)Proxy
.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
userService1.sleep();
userService1.eat();
}
}
InvocationHandler
InvocationHandler是一个接口,该接口中只有一个方法invoke。在该方法内可以实现一些代理类需要做的事情,比如日志处理,权限判断等等。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Proxy
Porxy
Proxy是动态代理类,负责代码在执行过程中通过调用newProxyInstance动态生成一个代理对象。这个代理对象继承了Proxy类并且和被代理类实现了同样的接口。
public static Object newProxyInstance(ClassLoader var0, Class>[] var1, InvocationHandler var2) {
Objects.requireNonNull(var2);
Class[] var3 = (Class[])var1.clone();
// 生成代理类的Class
Class var5 = getProxyClass0(var0, var3);
// 获取代理类的构造方法
final Constructor var6 = var5.getConstructor(constructorParams);
if (!Modifier.isPublic(var5.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
var6.setAccessible(true);
return null;
}
});
}
// 反射生成代理类对象
return var6.newInstance(var2);
}
$Proxy
Proxy的newProxyInstance方法会生成一个$Proxy类,通过这个类再生成代理对象。在调用newProxyInstance方法之前调用方法System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")就会在根目录下生成$Proxy类。(不同版本的jdk调用的方法不一样,具体可以看ProxyGenerator类里面的saveGeneratedFiles字段后面的字符串)
$Proxy继承了Proxy类并且和被代理类实现了同样的接口。$Proxy有一个构造方法,只有一个参数就是InvocationHandler接口,还有一些Method字段,一般前三个是不变的主要是toString、equals、hashCode后面的Method是实现的接口的Method。
$Proxy中实现的代理接口的方法,并且调用InvocationHandler的invoke方法,将被代理的一些信息传给invoke方法。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.lee.study.aop.dynamic.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void eat() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void sleep() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.lee.study.aop.dynamic.UserService").getMethod("eat");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.lee.study.aop.dynamic.UserService").getMethod("sleep");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
动态代理流程
1.首先初始化UserService,然后将初始化的Userservice作为参数传给InvocationHandler的构造方法
2.初始化InvocationHandler,并且将初始化了的InvocationHandler作为参数传递给$Proxy的构造方法
3.调用调用$Proxy的eat方法
4.在$Proyx的eat方法里面掉用了InvocationHandler的invoke方法
5.在InvocationHandler的invoke 方法里面通过反射调用了真正的eat方法,并且可以在invoke方法内调用eat方法前后做一些业务相关的操作。



