代理
- 静态代理(就是代理设计模式)
- 动态代理
- 基于接口的动态代理
- 基于子类的动态代理
静态代理
原始类
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();
静态代理的缺点:
- 有大量的冗余的代理类
- 代码维护成本高
- 需要声明的创建代理类。
动态代理
相对于静态代理,动态代理不需要声明式的创建代理类,在是运行过程中生成虚拟代理类。
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();
}
}