1.介绍
- 为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象,这样做的好处是可以在目标对象的方法基础上进行加强,即扩展目标对象的方法。
- 被代理的对象可以是远程对象、创建开销大的对象、或者需要安全控制的对象。
- 代理模式分主要为静态代理和动态代理,动态代理又分为JDK代理和Cglib代理。
2.静态代理
- 静态代理在使用时,代理对象和目标对象必须实现相同的接口或者继承相同的父类
- 场景模拟:你的体育老师喜欢规规矩矩上课,而数学老师总是喜欢在上课之前抽一根烟,有一天体育老师生病了,数学老师代上体育课。
代理对象:数学老师
目标对象:体育老师
类图:
代码
Teacher接口
package com.xzh.entity.proxy;
public interface Teacher {
public void teach();
}
MathTeacher 代理类
package com.xzh.entity.proxy;
public class MathTeacher implements Teacher {
public Teacher teacher;
public MathTeacher(Teacher teacher) {
this.teacher = teacher;
}
public void teach() {
System.out.println("体育老师不在,数学老师代课");
System.out.println("先抽烟---");
teacher.teach();
}
}
PETeacher
package com.xzh.entity.proxy;
public class PETeacher implements Teacher {
public void teach() {
System.out.println("上课");
}
}
Client客户端
package com.xzh.entity.proxy;
public class Client {
public static void main(String[] args) {
PETeacher peTeacher=new PETeacher();
MathTeacher mathTracher =new MathTeacher(peTeacher);
mathTracher.teach();
}
}
运行结果
3.JDK代理
- 代理对象不需要实现接口,但是目标对象需要实现接口,否则不能使用动态代理
- 代理对象的生成是利用JDK的API,动态的在内存中创建对象(java.lang.reflect.Proxy)
- 动态代理也叫JDK代理、接口代理
- JDK代理只需要使用newProxyInstance()方法
类图
Teacher接口
package com.xzh.entity.proxy;
public interface Teacher {
public void teach();
}
ProxyFactory
package com.xzh.entity.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("体育老师不在,数学老师上课");
System.out.println("抽烟-----");
Object returnValue = method.invoke(target, args);
System.out.println("上课结束");
return returnValue;
}
});
}
}
PETeacher
package com.xzh.entity.proxy;
public class PETeacher implements Teacher {
public void teach() {
System.out.println("上课");
}
}
Client
package com.xzh.entity.proxy;
public class Client {
public static void main(String[] args) {
PETeacher peTeacher=new PETeacher();
Teacher mathTeacher = (Teacher) new ProxyFactory(peTeacher).getProxyInstance();
mathTeacher.teach();
}
}
结果
4.Cglib代理
- 使用Cglib代理时目标对象不需要实现任何接口,而是使用目标对象的子类来实现代理
- Cglib也叫子类代理,他是从内存中创建一个目标对象的子类对象从而实现对目标对象功能的扩展
- Cglib是一个强大高性能的代码生成包,它可以在运行期间拓展Java类和实现Java接口,被广泛用于许多AOP框架
- AOP中如何选择代理模式
1、目标对象需要实现接口,JDK代理
2、目标对象不需要实现接口,Cglib代理 - Cglib包底层是通过使用字节码处理框架ASM来转换字节码并生成新的类的
注意
1、目标对象不能为finl类 否则报java.lang.illegalArgumentException
2、如果目标方法为static/finl 则不会被拦截即不会执行目标对象额外的业务方法
类图
代码
ProxyFactory
package com.xzh.entity.proxy;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyFactory implements MethodInterceptor {
public Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
//1、创建一个工具类
Enhancer enhancer = new Enhancer();
//2、设置父类
enhancer.setSuperclass(target.getClass());
//3、设置回调函数
enhancer.setCallback((Callback) this);
//4、创建子类对象,即代理对象
return enhancer.create();
}
//重写intercept方法,会调用目标对象的方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理开始");
System.out.println("体育老师生病了,数学老师代课");
System.out.println("抽烟----");
Object invoke = method.invoke(target);
return invoke;
}
}
PETeacher
package com.xzh.entity.proxy;
public class PETeacher {
public void teach() {
System.out.println("上课");
}
}
Client
package com.xzh.entity.proxy;
public class Client {
public static void main(String[] args) {
PETeacher peTeacher=new PETeacher();
PETeacher proxyFactory = (PETeacher) new ProxyFactory(peTeacher).getProxyInstance();
proxyFactory.teach();
}
}
结果