代理模式 Proxy Pattern
[摘自:百度百科]
组成
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
模式结构
一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理。对象实现同一个接口,先访问代理类再访问真正要访问的对象。
代理模式分为静态代理、动态代理。
静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
静态代理
代理对象和被代理对象实现相同的接口,但是代理对象持有被代理对象的引用。只能服务于一种类型的对象.对于稍大点的项目根本无法胜任.
// 接口
public interface Subject
{
public void doSomething();
}
// 目标类
public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}
// 代理类
public class SubjectProxy implements Subject
{
Subject subimpl = new RealSubject();
public void doSomething()
{
subimpl.doSomething();
}
}
//测试使用
public class TestProxy
{
public static void main(String args[])
{
Subject sub = new SubjectProxy();
sub.doSomething();
}
}
动态代理
- JDK动态代理
- 在JDK1.3之后加入了可协助开发的动态代理功能.不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象.
- 一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口.
- 通过InvocationHandler接口实现的动态代理只能代理接口的实现类.
实现动态代理,利用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法获得代理类,loader就是被代理类的类加载器,interfaces 是被代理类实现的接口,它实现了几个接口,就会为其生成几个相应的代理类。此外必须要实现InvocationHandler接口,重写其invoke方法,用java.lang.reflect.Method.invoke()方法调用目标方法(可以在调用之前或者之后添加代理服务方法)。}import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class LogHandler implements InvocationHandler{ //被代理的目标类 private Object targetObject; //创建代理 public Object createProxyInstance(Object targetObject){ this.targetObject=targetObject; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代理服务方法 insertLog(method,args); //调用目标方法(原业务逻辑) Object ret=method.invoke(targetObject, args); return ret; } private void insertLog(Method method,Object[] args){ System.out.println("logInfo:【methodName:"+method.getName()+";args:"+args+"】"); }
//测试
public class Client { public static void main(String[] args) { LogHandler logHandler=new LogHandler(); UserManager userManager=(UserManager)logHandler.createProxyInstance(new UserManagerImpl()); userManager.addUser(new User("杨园亮","123456")); OrderManager orderManager=(OrderManager)logHandler.createProxyInstance(new OrderManagerImpl()); orderManager.addOrder(new Order("杨园亮","6666")); } }
- cglib动态代理
- 添加jar包asm-commons-2.2.2.jar、asm-util-2.2.2.jar、asm-2.2.2.jar、cglib-nodep-2.1_3.jar。
//测试import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { // 设置需要创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); // 通过字节码技术动态创建子类实例 return enhancer.create(); } // 实现MethodInterceptor接口方法 public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable { //代理服务方法 insertLog(method,args); // 通过代理类调用父类中的方法 Object result = proxy.invokeSuper(obj, args); return result; } private void insertLog(Method method,Object[] args){ System.out.println("logInfo:【methodName:"+method.getName()+";args:"+args+"】"); } }
public class Client { public static void main(String[] args) { CglibProxy cglibProxy=new CglibProxy(); UserManagerImpl userManager=(UserManagerImpl)cglibProxy.getProxy(UserManagerImpl.class); userManager.addUser(new User("杨园亮","666666")); } }
区别
JDK实现动态代理的代理对象和目标对象必须实现相同的接口;Cglib实现动态代理的原理则是为目标对象创建一个子类座位代理对象。如果目标类实现了接口,则必须用JDK动态代理,否则,两个都可以用。