代理设计模式
代理设计模式的基本形式
代理设计模式的核心思路,一个接口两个子类,一个子类完成核心业务操作,另一个完成与核心业务有关的辅助性操作。例如,编写一个简单的设计模式。
package com.hbsi.test; interface Food{ public void eat(); } class ProxyFood implements Food{ private Food food; public ProxyFood(Food food) { this.food = food; } public void after() { System.out.println("饭后"); } public void before() { System.out.println("饭前"); } @Override public void eat() { this.after(); this.food.eat();//调用RealFood中的eat方法 this.before(); } } class RealFood implements Food{ @Override public void eat() { System.out.println("吃饭 ,,,,,RealFood"); } } public class ProxyDemo { public static void main(String[] args) { Food f = new ProxyFood(new RealFood()); f.eat(); } }
在什么情况下代理设计模式可能会被使用?最常用的形式就是在系统日志上进行,
动态代理类
传统的代理模式都是一个接口两个子类,一个是真实主题类,另一个是代理类,这样就导致了,一个代理类只能为一个接口服务,所以在java中提供了动态代理的支持。
如果要实现动态代理类,必须采用InvocationHandle接口处理。
此接口中定义了一个invoke方法:
处理代理实例上的方法调用并返回结果。
在这个invoke方法里面接受的参数如下,
1. proxy:代理的对象,
2. method:表示真实主题要调用的执行方法;
3. args:调用方法时所传递的参数
而在invoke'方法里面会返回一个Object的数据,这个数据就是调用方法时,返回的结果
但是所哟的真实主体累,都需要返回一个代理类对象,而这个代理类对象都由Proxy类完成,在Proxy类中的一个操作方法:
- public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。
在此方法中有以下参数:
loader :返回目标对象的类加载器;读取要代理类的代码,重新实例化一个新的
interfaces:返回一个类实现的所有接口
h:InvocationHandler 接口对象,完成真正的代理操作。
代码示例:建立一个动态代理类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyProxyd implements InvocationHandler{ private Object target;//要代理的对象信息 public Object bind(Object target) { this.target = target;//赋值 //返回与当前传入对象结构相同的代理类对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces() , this); } @Override//参数说明:代理的对象。表示真实主体类要执行的方法。方法需要的参数 public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable { this.log(); Object invoke = method.invoke(this.target, arg);//调用真实类的方法 this.commit(); return invoke; } private void log() { System.out.println("执行记录日志方法"); } private void commit() { System.out.println("事务提交"); } public static void main(String[] args) { Food f = (Food) new MyProxyd().bind(new RealFood()); f.eat(); } } public class RealFood implements Food{ @Override public void eat() { System.out.println("吃饭 ,,,,,RealFood"); } }
CGLIB代理模式、
从标准的代理设计模式来讲,一定要有借口,而且通过之前的动态代理也可以发现,如果想要去的代理类对象,就必须传入接口。
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces() , this);
使用Proxy必须传入所有接口,否则代理不能使用。为了解决java动态代理的必须需要接口的弊端,CGLIB可以解决此问题。
cglib包中需要使用以下几个类:
1. net.sf.cglib.proxy.Enhancer,相当于 Proxy 功能,返回代理对象
2. net.sf.cglib.proxy.MethodInterceptor接口:处理一个代理操作的接口
3. net.sf.cglib.proxy.MethodProxy:代替之前的Method类的功能
代码范例:基于类实现的动态代理设计模式
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class PrintMes { public void print() { System.out.println("吃饭 ,,,,,"); } } public class CGLIBProxy { public static void main(String[] args) { PrintMes mes = new PrintMes();// Enhancer enhancer = new Enhancer();//代理类对象 enhancer.setSuperclass(mes.getClass());//为代理类设置一个父类,自我理解就是做关联 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] objs, MethodProxy proxy) throws Throwable { System.out.println("饭前洗手"); return method.invoke(mes, args); } }); PrintMes create = (PrintMes) enhancer.create();//返回代理对象 create.print();//调用 } }