【结构型】- 代理模式
代理模式的定义:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式可以分为三种:静态代理,动态代理,cglib动态代理。
静态代理
服务接口
package com.java.pattern.proxy.staticdemo; public interface UserService { void eat(); }
服务具体实现(委托类)
package com.java.pattern.proxy.staticdemo; public class UserServiceImpl implements UserService { @Override public void eat() { System.out.println("感谢上帝,感谢神,我开动了..."); } }
服务静态代理类
package com.java.pattern.proxy.staticdemo; public class UserProxyServiceImpl implements UserService { private UserService userService; public UserProxyServiceImpl(UserService userService) { this.userService = userService; } @Override public void eat() { System.out.println("先点外卖....."); userService.eat(); System.out.println("清理外卖....."); } }
测试类
package com.java.pattern.proxy.staticdemo; public class Ctest01 { public static void main(String[] args) { UserService userService = new UserServiceImpl();// 使用静态代理,在不改变eat()方法代码的前提下,增强功能(添加额外的功能服务) userService = new UserProxyServiceImpl(userService); userService.eat(); } }
测试结果:
先点外卖.....
感谢上帝,感谢神,我开动了...
清理外卖.....
优点:
- 在不改变委托类代码的前提下,为委托类添加额外的功能。
缺点:
- 代理类和委托类需要实现同一接口。
- 一个代理类只能代理一个服务,这就导致我们需要为每一个服务都创建代理类。
- 委托类实现的接口,一旦发生改变,代理类也要修改代码。
jdk动态代理
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
动态代理类
public class DynamicProxyService implements InvocationHandler { private Object target; public DynamicProxyService(Object target) { this.target = target; } public Object getProxyInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理类[DynamicProxyService] before doSomething..."); Object res = method.invoke(target, args); System.out.println("代理类[DynamicProxyService] after doSomething..."); return res; } }
代理的目标对象:接口的实现类
public interface TargetService { String doSomething(String params); }
public class TargetServiceImpl implements TargetService { @Override public String doSomething(String params) { System.out.println("[TargetServiceImpl]doSomething..."); return null; } }
代理的目标对象:类的继承类(子类)
public class TargetClass { /** * 普通方法 */ public void doSomething() { System.out.println("[TargetClass]doSomething..."); } /** * final方法 */ public final void finalFunction() { System.out.println("[TargetClass]finalFunction..."); } }
public class TargetSubClass extends TargetClass { @Override public void doSomething() { System.out.println("[TargetSubClass]doSomething..."); } }
测试类:
public class Ctest01 { public static void main(String[] args) { testJDKDynamicProxy(); } public static void testJDKDynamicProxy() { System.out.println("---> 代理对象:接口的实现类"); // 目标类 TargetService targetService = new TargetServiceImpl(); // 代理类 DynamicProxyService dynamicProxyService = new DynamicProxyService(targetService); // 获取代理对象 targetService = (TargetService)dynamicProxyService.getProxyInstance(); targetService.doSomething("params"); System.out.println("----------------------------------------------------------------"); System.out.println("---> 代理对象:继承类"); // 目标类 TargetClass targetClass = new TargetSubClass(); // 代理类 dynamicProxyService = new DynamicProxyService(targetClass); // 获取代理对象 targetClass = (TargetClass) dynamicProxyService.getProxyInstance(); targetClass.doSomething(); } }
测试结果:
---> 代理对象:接口的实现类
代理类[DynamicProxyService] before doSomething...
[TargetServiceImpl]doSomething...
代理类[DynamicProxyService] after doSomething...
----------------------------------------------------------------
---> 代理对象:继承类
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy1 cannot be cast to com.design.pattern.proxy.target.TargetClass
at com.design.pattern.proxy.Ctest01.testJDKDynamicProxy(Ctest01.java:43)
at com.design.pattern.proxy.Ctest01.main(Ctest01.java:15)
优点:
- 在不改变委托类代码的前提下,为委托类添加额外的功能。
- 代理类无需和委托类实现同一接口。
- 一个代理类能够代理所有委托类
缺点:
- 委托类必须要实现某一接口或继承某一父类
cglib动态代理
JDK实现动态代理需要目标类实现某一接口,对于没有实现任何接口的类,该如何实现动态代理呢,这就需要CGLib了,CGLIB(Code Generation Library)是一个代码生成的类库。采用了非常底层的字节码技术,其原理是通过字节码技术在运行时为指定类创建一个子类对象,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的目标类,以及目标类中的final方法进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
委托类
public class TargetClass { /** * 普通方法 */ public void doSomething() { System.out.println("[TargetClass]doSomething..."); } /** * final方法 */ public final void finalFunction() { System.out.println("[TargetClass]finalFunction..."); } }
cglib代理类
package com.design.pattern.proxy.cglibmode;
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 CglibProxyService implements MethodInterceptor {
private Object target;
public CglibProxyService(Object target) {
this.target = target;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理类[CglibProxyService] before doSomething...");
Object res = method.invoke(target, args);
System.out.println("cglib代理类[CglibProxyService] after doSomething...");
return res;
}
}
测试类
package com.design.pattern.proxy; import com.design.pattern.proxy.cglibmode.CglibProxyService; import com.design.pattern.proxy.jdkmode.DynamicProxyService; import com.design.pattern.proxy.staticmode.ProxyService; import com.design.pattern.proxy.target.TargetClass; import com.design.pattern.proxy.target.TargetService; import com.design.pattern.proxy.target.TargetServiceImpl; import com.design.pattern.proxy.target.TargetSubClass; public class Ctest01 { public static void main(String[] args) { testCglibProxy(); } public static void testCglibProxy() { // 目标类 TargetClass targetClass = new TargetClass(); // 代理类 CglibProxyService cglibProxyService = new CglibProxyService(targetClass); // 获取代理对象 targetClass = (TargetClass)cglibProxyService.getProxyInstance(); targetClass.doSomething(); // 测试cglib动态代理是否能代理final方法 targetClass.finalFunction(); } }
测试结果如下:
cglib代理类[CglibProxyService] before doSomething...
[TargetClass]doSomething...
cglib代理类[CglibProxyService] after doSomething...
[TargetClass]finalFunction...
优点:
- 在不改变委托类代码的前提下,为委托类添加额外的功能。
- 代理类无需和委托类实现同一接口。
- 一个代理类能够代理所有委托类
- 相比于JDK动态代理,委托类无需要实现某一接口或继承某一父类。
缺点:
- 委托类不能是final类,因为final类无法被继承。