(12)代理模式
概念
对一个对象生成一个新的代理对象,代理对象具备原对象的功能,且能对原对象的功能进行增强。很像装饰模式,但是装饰模式只是把对象的某个方法进行增强,而代理模式把整个对象的所有方法都增强。
例如:每个人都会睡午觉,也会睡晚觉。我现在希望每个人睡午觉的前后都刷牙,睡晚觉的前后也都刷牙
实现方式
JDK代理
对目标类的接口生成代理类,代理类中会保存目标类的对象,代理类在调用目对象的方法前后能做一些操作,比如记录目标类的方法执行时间
使用JDK代理时,目标类必须有接口,否则不能使用JDK代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK代理。被代理的类必须实现接口
*/
public class Demo {
public static void main(String[] args) {
Person person = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), new Class[]{Person.class}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("睡觉前先刷牙");
Object result = method.invoke(new Student(), objects);
System.out.println("睡醒后也要刷牙");
return result;
}
});
person.noonSleep();
System.out.println("===========");
person.nightSleep();
}
}
interface Person {
void noonSleep();
void nightSleep();
}
// 被代理的类必须实现接口,否则无法使用JDK代理
class Student implements Person {
public void noonSleep() {
System.out.println("中午睡觉");
}
@Override
public void nightSleep() {
System.out.println("晚上睡觉");
}
}
睡觉前先刷牙
中午睡觉
睡醒后也要刷牙
===========
睡觉前先刷牙
晚上睡觉
睡醒后也要刷牙
cglib 代理
对目标类生成代理类,其实代理类就是目标类的子类。代理类由于继承了目标类,所以代理类可以在调用目标类方法的前后做一些操作,比如记录目标类的方法执行时间
使用CGLIB代理时,目标类可以不用实现某个接口
先引入cglib包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB代理。被代理的类可以不实现接口
*/
public class Demo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Student.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("睡觉前先刷牙");
Object result = method.invoke(new Student(), objects);
System.out.println("睡醒后也要刷牙");
return result;
}
});
Student s = (Student) enhancer.create();
s.noonSleep();
System.out.println("===========");
s.nightSleep();
}
}
// 不实现接口也能代理
class Student {
public void noonSleep() {
System.out.println("中午睡觉");
}
public void nightSleep() {
System.out.println("晚上睡觉");
}
}
睡觉前先刷牙
中午睡觉
睡醒后也要刷牙
===========
睡觉前先刷牙
晚上睡觉
睡醒后也要刷牙