代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时,我们就可以返回该对象的代理。
通常情况下,适用代理模式的情况有两种:
1.创建对象开销很大,可以创建一个代理对象,推迟真正的对象创建。大家所熟悉的Hibernate延迟加载策略就是使用动态代理,当A实体关联B实体时,在获取A实体时不需要立即获得与A实体关联的B实体,因为有可能客户端根本不需要B实体数据,当客户端真正需要这部分数据时,再加载B实体的数据。这样就节省了资源。
2.所创建的对象不能满足客户端需求,比如说我们需要为某个方法运行前加入一些验证或者过滤,这时我们就需要创建一个代理对象,增强原来对象的功能。
java实现动态代理有两种方法:jdk代理和cglib。
public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }代理类要实现这个接口,并实现Invoke方法,这个就是代理方法,当客户端调用委托对象方法时,实际上执行Invoke方法。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException下面看一个jdk动态代理的例子:
public interface IPerson { void walk(); }定义实现类
public class Person implements IPerson { @Override public void walk() { System.out.println("walk"); } }定义代理实现类
public class MyInvokationHandler implements InvocationHandler { private Object target; public void setTarget(Object target) { this.target=target; } /** * 执行动态代理对象的所有方法时,都会被替换执行如下的invoke方法 * Proxy:代表动态代理的对象 * method:代表正在执行的方法 * args:代表调用目标方法时传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("正在执行的方法:"+method); method.invoke(target, args); return null; } }
public class ProxyTest { /** * @param args */ public static void main(String[] args) { MyInvokationHandler handler =new MyInvokationHandler(); Person person=new Person(); handler.setTarget(person); IPerson p=(IPerson)Proxy.newProxyInstance(Person.class.getClassLoader(), Person.class.getInterfaces(), handler); p.walk(); } }
1、创建一个实现net.sf.cglib.proxy.MethodInterceptor接口的实例来为目标业务类加入进行代理时要进行的操作或增强:
import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; /** *CGlib采用非常底层的字节码技术,可以为一个类创建子类, 并在子类中采用方法拦截技术拦截父类方法的调用,并顺势进行增强,即是织入横切逻辑 * @author tufu */ public class CglibProxy implements MethodInterceptor{ private Enhancer enhancer = new Enhancer(); //覆盖MethodInterceptor接口的getProxy()方法,设置 public Object getProxy(Class clazz){ enhancer.setSuperclass(clazz); //设者要创建子类的类 enhancer.setCallback(this); //设置回调的对象 return enhancer.create(); //通过字节码技术动态创建子类实例, } public Object intercept(Object obj,Method method,Object[] args, MethodProxy proxy) throws Throwable { System.out.println("模拟代理增强方法"); //通过代理类实例调用父类的方法,即是目标业务类方法的调用 Object result = proxy.invokeSuper(obj, args); System.out.println("模拟代理增强方法结束"); return result; } }
2、通过java.lang.reflect.Proxy的getProxy()动态生成目标业务类的子类,即是代理类,再由此得到代理实例:
import com.proxy.ForumServiceImpl; import java.lang.reflect.Proxy; public class TestCglibProxy { public static void main(String args[]){ CglibProxy proxy = new CglibProxy(); //动态生成子类的方法创建代理类 ForumServiceImpl fsi = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class); fsi.removeForum(10); fsi.removeTopic(2); } }