代理模式详解
代理模式为对象提供一个代理以控制对这个对象的访问。所谓代理,是指与代理元(即:被代理的对象)具有相同接口的类,客户端必须通过代理与代理元进行交互。我们可以将代理理解成另一个对象的代表。
代理(proxy)模式本质上就是通过一个代理对象访问目标对象,而不直接访问目标对象;代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。这么做的好处是,可以让目标对象只关注业务逻辑,而非业务逻辑(比如日志输出等)可以在代理对象中实现,实现业务分离。
代理模式要点:
- 代理模式包含三个要素:1)接口/Interface; 2)代理元/Target:即被代理的对象; 3)代理类/Proxy:代理元的代表,对外提供访问;
- 代理元与代理类都是接口的实现类;
- 客户端只能访问代理类,无法直接访问代理元;
代理分为静态代理和动态代理。
静态代理
静态代理就是在编译时生成代理类。即:通过编码手动创建代理类,并在代理类中调用代理元。
编码实现
1.接口
package effectiveJava.proxy; public interface HelloService { void sayHello(); }
2,代理元
package effectiveJava.proxy; public class HelloServiceImpl implements HelloService{ @Override public void sayHello() { System.out.println("Hello Proxy."); } }
3,代理类
package effectiveJava.proxy.staticProxy; import effectiveJava.proxy.HelloService; public class LogProxy implements HelloService { private HelloService service; public LogProxy(HelloService service) { this.service = service; } @Override public void sayHello() { System.out.println("Static Proxy : Before Hello...."); service.sayHello(); System.out.println("Static Proxy : After Hello...."); } }
4,测试类
package effectiveJava.proxy.staticProxy; import effectiveJava.proxy.HelloServiceImpl; public class LogProxyDemo { public static void main(String[] args) { LogProxy logProxy = new LogProxy(new HelloServiceImpl()); logProxy.sayHello(); } }
5,测试结果
Static Proxy : Before Hello....
Hello Proxy.
Static Proxy : After Hello....
动态代理
动态代理地实现有两种方式:1)基于JDK的动态代理;2)基于CGLIB的动态代理;
1)基于JDK的动态代理
API
public class Proxy implements java.io.Serializable { /** * 创建代理实例 * @param loader 代理元的类加载器 * @param interfaces 代理元的接口 * h 一个 InvocationHandler 对象 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h); }
/** * * 每个代理的实例都有一个与之关联的 InvocationHandler 实现类, * 如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。 */ public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
编码实现
1,接口、代理元(编码与静态代理一致,不再赘述)
2,代理类(必须实现InvocationHandler接口)
package effectiveJava.proxy.v0; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class HelloInvocation implements InvocationHandler { /** * 代理元 */ private Object target; public HelloInvocation(Object target) { this.target = target; } /** * * @param proxy 代理类实例 * @param method 实际要调用的方法 * @param args 实际要调用方法的参数类型 * @return 结果值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("HelloInvocation : Before Hello...."); Object reslut = method.invoke(target, args); System.out.println("HelloInvocation : After Hello...."); return reslut; } }
3,测试类
package effectiveJava.proxy.v0; import effectiveJava.proxy.HelloService; import effectiveJava.proxy.HelloServiceImpl; import java.lang.reflect.Proxy; /** * 通过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建代理对象的实例 */ public class HelloInvocationDemo { public static void main(String[] args) { HelloServiceImpl helloService = new HelloServiceImpl(); HelloInvocation helloInvocation = new HelloInvocation(helloService); HelloService impl = (HelloService)Proxy.newProxyInstance( helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), helloInvocation); impl.sayHello(); } }
4,测试结果
HelloInvocation : Before Hello....
Hello Proxy.
HelloInvocation : After Hello....
2)基于CGLIB的动态代理
Cglib是基于继承的方式进行代理,代理类去继承目标类,每次调用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类的该方法的逻辑。因此,基于CGLIB的动态代理不需要接口。
编码实现
1,引入架包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
2,代理类(HelloServiceImpl.java,编码与静态代理一致)
3, 方法拦截器
package effectiveJava.proxy.cglib; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class LogInterceptor implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib : Before hello..."); //调用父委方法 Object result = methodProxy.invokeSuper(object, args); System.out.println("Cglib : After hello..."); return result; } }
4,测试类
package effectiveJava.proxy.cglib; import effectiveJava.proxy.HelloService; import effectiveJava.proxy.HelloServiceImpl; import net.sf.cglib.proxy.Enhancer; public class CglibDemo { public static void main(String[] args) { //创建Enhancer对象,类似于JDK动态代理的Proxy类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(HelloServiceImpl.class); //设置回调函数(拦截器) enhancer.setCallback(new LogInterceptor()); //创建代理类实例 HelloService service = (HelloService)enhancer.create(); service.sayHello(); } }
5,测试结果
Cglib : Before hello...
Hello Proxy.
Cglib : After hello...
总结:
- 静态代理是在编译时创建代理,动态代理是在运行时创建代理;
- JDK动态代理是基于接口的方式,CGLib动态代理是基于继承;
更多内容,请访问:http://www.cnblogs.com/BlueStarWei