代理模式:为对象提供一种代理来控制对象的访问。
代理模式分为静态代理和动态代理两种
- 静态代理:
- 优点:通过代理类可以对目标类进行扩展;
- 缺点:每个代理类需要实现委托对象的接口,如果接口增加方法,就需要修改代理类;其次,每一个代理类对应一个委托对象,如果委托对象比较多的话,代理类就非常臃肿;
静态代理的实现:
/**
* 被代理接口定义
*/
public interface Person {
/**
* 交作业
*/
void giveTask();
}
/**
* 目标对象
*/
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void giveTask() {
System.out.println(String.format("%s交语文作业", name));
}
}
/**
* 代理类
*/
public class StudentsProxy implements Person {
Student stu;
public StudentsProxy(Student stu) {
// 只代理学生对象
if (stu.getClass() == Student.class) {
this.stu = stu;
}
this.stu = stu;
}
//代理交作业,调用被代理学生的交作业的行为
@Override
public void giveTask() {
stu.giveTask();
}
}
/**
* 静态代理测试
*/
@Test
public void staticProxy() {
//被代理的学生林浅,他的作业上交有代理对象monitor完成
Student linqian = new Student("林浅");
//生成代理对象,并将林浅传给代理对象
Person monitor = new StudentsProxy(linqian);
//班长代理交作业
monitor.giveTask();
}
- 动态代理:代理类需要实现InvocationHandler接口,重写invoke方法;
- JDK动态代理:利用基于反射和拦截器实现;并且要求代理对象必须实现接口;
- CGLIB动态代理:利用ASM开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。主要是对指定的类生成一个子类,覆盖其中的方法,进行增强;但是因为采用的继承,对于final类的方法,是无法继承的;CGLIB采用了fastclass原理,是将方法进行编号,通过编号找到方法避免了通过反射调用。
动态代理代码的实现:
/**
* 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,
* 当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke方法来进行调用。
*/
public class StuInvocationHandler<T> implements InvocationHandler {
//invocationHandler持有的被代理对象
T target;
public StuInvocationHandler(T target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
return method.invoke(target, args);
}
}
/**
* @description 动态代理类
*/
public class JdkFuDao implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target) {
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始挑选老师");
Object result = method.invoke(this.target, args);
System.out.println("双方同意,开始辅导");
return result;
}
}
/**
* @description 目标对象一定要实现接口,否则不能用动态代理
*/
public class ZhaoLiu implements IPerson {
@Override
public void findTeacher() {
System.out.println("符合赵柳的要求");
}
}
/**
* 动态代理测试
*/
@Test
public void testZhaoLiu() {
JdkFuDao jdkFuDao = new JdkFuDao();
// 获取代理对象
IPerson zhaoLiu = jdkFuDao.getInstance(new ZhaoLiu());
zhaoLiu.findTeacher();
}
网友评论