什么是代理模式
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
静态代理
接下来用java代码举例一个儿子找对象,父亲帮忙相亲的静态代理的例子。 接口
public interface Person {
void findLove();
}
被代理类
public class Son implements Person {
@Override
public void findLove(){
System.out.println("Son找对象要肤白貌美");
}
}
** 代理类**
public class Father implements Person{
private Person person;
public Father(Person person) {
this.person = person;
}
public void findLove(){
System.out.println("父亲物色对象");
this.person.findLove();
System.out.println("双方同意,确认关系");
}
}
测试用例
public class FatherproxyTest {
public static void main(String[] args) {
Father father = new Father(new Son());
father.findLove();
}
}
运行结果
java静态代理优缺点
优点: 在客户端与目标对象之间起到一个中介作用和保护目标对象的作用; 代理对象可以扩展目标对象的功能; 能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性
其主要缺点是: 会造成系统设计中类的数量增加 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢; 增加了系统的复杂度; 那么如何解决以上提到的缺点呢?答案是可以使用动态代理方式
动态代理
动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。
java动态代理例子
Gril类
public class Gril implements Person {
@Override
public void findLove() {
System.out.println("高富帅");
System.out.println("身高180");
System.out.println("要求程序员");
}
}
Matchmaker类
public class Matchmaker implements InvocationHandler {
private Person target;
public Object getInstance(Person person){
this.target = person;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.target, args);
after();
return obj;
}
private void before(){
System.out.println("媒婆根据筛选");
System.out.println("开始收钱");
}
private void after(){
System.out.println("OK成功,拿到尾款");
}
}
** 测试类**
public class ProxyTest {
public static void main(String[] args) throws IOException {
Person obj = (Person) new Matchmaker().getInstance(new Gril());
obj.findLove();
}
}
运行结果
java动态代理原理
有人肯定很好奇,JDK是怎么实现的,为什么能够调用到invoke方法
根据上面的debug,我们可以发现,在程序运行期间创建了一个对象为proxy0的,那我们将它打输出来,看看里面的内容。
下面将上诉代码进行一下修改。
Person obj = (Person) new Matchmaker().getInstance(new Gril());
obj.findLove();
// 生成代理类的字节码
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
// 输出到相关路径下
FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
fos.write(bytes);
fos.close();
$Proxy0
public final class $Proxy0 extends Proxy implements Person {
// 四个静态方法 下方静态初始化
private static Method m1;
private static Method m3;
private static Method m2;
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 findLove() throws {
try {
// 调用invoke方法
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);
}
}
静态初始化m0-m4
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
// 被代理的方法
m3 = Class.forName("proxy.Person").getMethod("findLove");
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());
}
}
}
上述代码的构造方法可以看到,传入了InvocationHandler var1,传入进去的就是Matchmaker,因为matchmaker实现了InvocationHandler,另外在findLove方法里有 super.h.invoke(this, m3, (Object[])null); 因此这也是为什么调用findlove方法,底层还执行了**invoke**方法的原因。
动态代理使用场景
SpringAOP
Spring框架中我们常用的AOP面向切面编程,其底层原理就是运用的动态代理,通过生成一个代理类,来进行方法执行前后的增强,例如日志输出,懒加载等。 @Before 前置增强
@AfterReturning 返回增强
@After 后置增强
@AfterThrowing 异常增强
@Around 环绕增强
Spring中以上的几种增强都是通过动态代理的方式,具体源代码就需要通过大家自己去看了。
世界晚安!