跳到主要内容

代理

  • 静态代理(就是代理设计模式)
  • 动态代理
    • 基于接口的动态代理
    • 基于子类的动态代理

静态代理

原始类

package com.wangzhy.interview.design.proxy;

public class Student implements Person {

private String name;

public Student() {
}

public Student(String name) {
this.name = name;
}

@Override
public void wakeup() {
System.out.println("学生" + name + "早晨醒来啦");
}

@Override
public void sleep() {
System.out.println("学生" + name + "晚上睡觉啦");
}
}

代理类:在代理类中持有原始类的引用,然后在代理类中调用原始类的方法。

package com.wangzhy.interview.design.proxy;

public class PersonProxy implements Person {

private Person person;

public PersonProxy(Person person) {
this.person = person;
}

@Override
public void wakeup() {
System.out.println("早安~");
person.wakeup();
}

@Override
public void sleep() {
System.out.println("晚安~");
person.sleep();
}
}

使用代理类

Person student = new Student("张三");
PersonProxy studentProxy = new PersonProxy(student);
studentProxy.wakeup();
studentProxy.sleep();

静态代理的缺点:

  1. 有大量的冗余的代理类
  2. 代码维护成本高
  3. 需要声明的创建代理类。

动态代理

相对于静态代理,动态代理不需要声明式的创建代理类,在是运行过程中生成虚拟代理类。

JDK 动态代理

package com.wangzhy.interview.design.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {

private Object bean;

public JdkProxy(Object bean) {
this.bean = bean;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (methodName.equals("wakeup")) {
System.out.println("早安~~~");
} else if (methodName.equals("sleep")) {
System.out.println("晚安~~~");
}

return method.invoke(bean, args);
}

public static void main(String[] args) {
JdkProxy proxy = new JdkProxy(new Student("张三"));
Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
new Class[]{Person.class}, proxy);
student.wakeup();
student.sleep();
}
}

Cglib 动态代理

  • jdk 动态代理只能基于接口,代理生成的对象只能赋值给接口变量,而 Cglib 不存在这个问题。
  • cglib 速度比 jdk 动态代理快。

cglib 底层采用了 ASM 字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并从写了类的所有可以重写的方法, 在重写的过程中,将我们定义的额外的逻辑织入方法中,对方法进行了增强。而通过字节码操作生成的代理类,和我们自己编写并编译后的类没有太大的区别。

  • cglib 不能代理 final 、static 修饰的类和方法。
package com.wangzhy.interview.design.proxy;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

private Enhancer enhancer = new Enhancer();

private Object bean;

public CglibProxy(Object bean) {
this.bean = bean;
}

public Object getProxy() {
//设置需要创建子类的类
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}

//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
String methodName = method.getName();
if (methodName.equals("wakeup")) {
System.out.println("早安~~~");
} else if (methodName.equals("sleep")) {
System.out.println("晚安~~~");
}

//调用原bean的方法
return method.invoke(bean, args);
}

public static void main(String[] args) {
CglibProxy proxy = new CglibProxy(new Student("张三"));
Student student = (Student) proxy.getProxy();
student.wakeup();
student.sleep();
}
}