代理模式
代理模式(Proxy Pattern)为其他类提供代理控制对象访问,属于结构型模式,满足开闭原则。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
例子
- 买火车票不一定去火车站买也可以去代售点买
- 卖房子可以委托中介帮卖
- 电脑桌面创建快捷方式
分类
代理模式分为静态代理,动态代理。
静态代理:程序员自己写的代理类
动态代理:分为Jdk和CJLB动态代理方式
静态代理
使用代理方式在执行order前后增加日志纪录操作
package com.mode.proxy;
public interface OrderService {
public void order();
}
package com.mode.proxy;
public class Order implements OrderService{
public void order(){
System.out.println("订单操作------->start");
System.out.println("订单操作------->end");
}
}
package com.mode.proxy;
public class StaticProxy implements OrderService{
private Order order;
public StaticProxy(Order order){
this.order = order;
}
@Override
public void order() {
System.out.println("日志记录开始---------->");
this.order.order();
System.out.println("日志记录结束---------->");
}
}
package com.mode.proxy;
public class TestProxy {
public static void main(String[] args) {
new StaticProxy(new Order()).order();
}
}
静态代理可以对接口进行增强,如上案例中对订单增加了日志处理,假如我们登陆、支付等操作都要日志处理不可能写很多这样的代理类,这时引入动态代理方式。
动态代理->Jdk动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
参数解析:
Object proxy--------->Jvm生成的被代理类的动态代理对象
Method method----->代理对象中的你要调用的方法
Object[] args--------->你调用代理对象传递的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
Proxy.newProxyInstance参数解析:
CLassLoader loader------->被代理对象的类加载器
Class<?> interfaces------->被代理类全部的接口
InvocationHandler h------->实现InvocationHandler接口的对象
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
在invoke中日志处理。
package com.mode.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkOrderProxy implements InvocationHandler {
//Object类型动态代理
private Object obj;
public Object newProxyInstance(Object object){
this.obj=object;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("日志记录开始---------->"+args);
Object invoke = method.invoke(obj, args);
System.out.println("日志记录开始---------->");
return invoke;
}
public static void main(String[] args) {
JdkOrderProxy orderProxy = new JdkOrderProxy();
Object newProxyInstance = orderProxy.newProxyInstance(new Order());
OrderService orderService=(OrderService)newProxyInstance;
orderService.order();
}
}
动态代理->Cjlb动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
package com.mode.proxy;
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 CJlbProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("日志记录开始---------->");
Object invoke = methodProxy.invoke(o, objects);
System.out.println("日志记录开始---------->");
return invoke;
}
public static void main(String[] args) {
//Enhancer为字节码增强器,很方便对类进行扩展
Enhancer enhancer = new Enhancer();
//传入被代理类
enhancer.setSuperclass(Order.class);
//传入实现MethodInterceptor接口对象
enhancer.setCallback(new CJlbProxy());
返回代理对象,是被代理类的子类
Order order = (Order) enhancer.create();
//调用
order.order();
}
}
如何选用
1、如果目标对象实现了接口,两种都可以用。
2、如果目标对象没有实现了接口,必须采用CGLIB库。
总结
1、JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:
-
实现InvocationHandler
-
使用Proxy.newProxyInstance产生代理对象
-
被代理的对象必须要实现接口
2、CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类。