Java 代理模式
发布于: 3 小时前
代理模式主要是在不改变原有方法的前提对方法进行增强!
静态代理
ISubject.java
public interface ISubject {
void sayHello();
}
复制代码
SubjectImpl.java
public class SubjectImpl implements ISubject {
@Override
public void sayHello() {
System.out.println("HELLO WORLD");
}
}
复制代码
Proxy.java
public class Proxy implements ISubject {
private ISubject target;
public Proxy(ISubject target) {
this.target = target;
}
@Override
public void sayHello() {
System.out.println("调用方法前");
target.sayHello();
System.out.println("调用方法后");
}
}
复制代码
TestStaticProxy.java
public class TestStaticProxy {
public static void main(String[] args) {
ISubject target = new SubjectImpl();
ISubject proxy = new Proxy(target);
proxy.sayHello();
}
}
复制代码
结果
调用方法前
HELLO WORLD
调用方法后
复制代码
静态代理,本质上是利用了 Java 中的多态,代理对象通过持有被代理对象的
缺点:扩展性差
JDK 动态代理
定义对被代理的类增强的处理类(即,被代理的类的方法都需要经过该类处理)
JdkProxy.java
public class JdkProxy implements InvocationHandler {
private ISubject target;
public JdkProxy(ISubject target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk proxy 调用方法前");
target.sayHello();
System.out.println("jdk proxy 调用方法后");
return null;
}
}
复制代码
TestJdkProxy
public class TestJdkProxy {
public static void main(String[] args) {
ISubject target = new SubjectImpl();
ISubject jdkProxy = (ISubject) Proxy.newProxyInstance(
ISubject.class.getClassLoader(),
new Class<?>[]{ISubject.class},
new JdkProxy(target)
);
jdkProxy.sayHello();
}
}
复制代码
输出
jdk proxy 调用方法前
HELLO WORLD
jdk proxy 调用方法后
复制代码
可以在 com.sun.proxy 的路径中看到一个 $Proxy0.class
package com.sun.proxy;
import com.gingo.training.camp.week05.work.aop.statico.proxy.ISubject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// 动态代理类 实现了 ISubject
public final class $Proxy0 extends Proxy implements ISubject {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
// var1 就是 new JdkProxy(target)
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
// super.h 就是 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);
}
}
// 将 参数交给 InvocationHandler 的 invoke 方法,
// 又因为 InvocationHandler 持有 原有方法的引用可以基于增强
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (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 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"));
m3 = Class.forName("com.gingo.training.camp.week05.work.aop.statico.proxy.ISubject").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
复制代码
本质上还是利用了 Java 接口的多态,但是这里有一个有趣的地方,就是 Java 可以在运行期生成类,并通过我们指定的类加载器加载。即多态 + 运行期生成类并加载
优点:扩性比静态代理前
缺点:只能代理接口
CGLIB
引入 cglib 依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
复制代码
定义一个普通的类
Subject.java
public class Subject {
public void sayHello() {
System.out.println("HELLO WORLD");
}
}
复制代码
TestCglibProxy.java
public class TestCglibProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Subject.class);
enhancer.setCallback(
(MethodInterceptor) (obj, method, argss, proxy) -> {
System.out.println("jdk proxy 调用方法前");
Object result = proxy.invokeSuper(obj, argss);
System.out.println("jdk proxy 调用方法后");
return result;
}
);
Subject cglibProxy = (Subject) enhancer.create();
cglibProxy.sayHello();
}
}
复制代码
输出
cglib proxy 调用方法前
HELLO WORLD
cglib proxy 调用方法后
复制代码
本质通过 ASM 技术对字节码注入,实现原有的方法进行增强
优点:可以代理普通的类,不需要实现特定的接口
划线
评论
复制
发布于: 3 小时前阅读数: 7
gin
关注
还未添加个人签名 2020.01.17 加入
真正的大师永远怀着一颗学徒的心
评论