1、基本介绍:
为对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,这样的好处是可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
代理模式可分为静态代理和动态代理,动态代理包括JDK代理和cglib代理,下面依次介绍
2、静态代理:
静态代理需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同的父类。
定义一个接口:
public interface MyInterface {
void solve(String name);
}
被代理类实现这个接口:
public class MyImpl implements MyInterface {
@Override
public void solve(String name) {
System.out.println(name+"调用了该方法");
}
}
代理类实现同样一个接口并且持有一个被代理对象的引用:
public class MyProxy implements MyInterface{
private MyInterface myInterface;
public MyProxy(MyInterface myInterface){
this.myInterface = myInterface;
}
@Override
public void solve() {
System.out.println("Before......" );
myInterface .solve();
System.out.println("After......");
}
}
使用代理类:
public static void main(String[] args) {
// 创建被代理类对象
MyInterface myInterface = new MyImpl("bipa");
// 创建代理类对象
MyProxy myProxy = new MyProxy(myInterface);
// 调用方法
myProxy .solve();
}
静态代理优缺点:
- 在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展
- 由于代理对象需要与目标对象实现一样的接口,所以会有很多代理类
- 一旦接口增加方法,目标对象与代理对象都要维护
3、动态代理
3.1、JDK动态代理
基本介绍:
- 代理对象不需要实现接口,但是目标对象要实现接口
- 利用JDK的API动态的在内存中构建代理对象
- JDK动态代理又叫接口代理
具体步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器
- 通过为 Proxy 类指定被代理类的 ClassLoader 对象和一组 interface 来创建动态代理类
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
代码实现如下:
public class TestJDKProxy {
public static void main(String[] args) {
MyImpl myImpl = new MyImpl();
MyInterface mi = (MyInterface) Proxy.newProxyInstance(myImpl.getClass().getClassLoader(),myImpl.getClass().getInterfaces(),
(proxy,method,arg) -> {
System.out.println("前");
Object res = null;
res = method.invoke(myImpl,arg);
System.out.println("后");
return res;
});
mi.solve("bipa");
}
}
JDK动态代理底层使用反射机制进行方法的调用,不过只能够代理实现了接口的委托类。
3.2、Cglib代理
基本介绍:
- 静态代理和JDK代理都要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理,即Cglib代理
- Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展
- Cglib是一个强大的高性能的代码生成包,可以在运行期扩展java类与实现java接口,广泛的被许多AOP框架使用,如Spring AOP,实现方法拦截
- Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类
代码演示:
引入第三方包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
定义被代理类
public class MyImpl {
public void solve(){
System.out.println("solving...");
}
}
定义方法拦截器
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before:"+method.getName());
Object object = methodProxy.invokeSuper(o,objects);
System.out.println("After:"+method.getName());
return object;
}
}
生成代理类对象并调用方法
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyImpl.class);// 继承被代理类
enhancer.setCallback(new MyMethodInterceptor());// 设置回调
MyImpl my = (MyImpl) enhancer.create();// 生成代理类对象
my.solve();// 使用代理类调用方法时会被实现的方法拦截器拦截
}
}
运行结果
Before:solve
solving...
After:solve
注意:Cglib不能对final类以及final/static方法进行代理。
至此,代理模式的介绍完毕