设计模式之代理模式
代理模式是比较重要的设计模式之一,在面向对象的系统中,有些对象由于某些原因(比如创建对象的开销很大,或者某些操作需要安全校验机制,或者其他的额外控制),典型应用就是AOP。
主要分为静态代理和动态代理,静态代理就是通过java代码写死代理类,动态代理就是动态的生成代理类,主要分为jdk动态代理和cglib动态代理,区别是jdk动态代理需要被代理的对象必须有父类,运行时动态的生成父类的子类,也就是代理类和被代理类是同一个父类,跟静态代理差不多,cglib动态代理则没有这个限制,运行的时候动态生成被代理类的子类。
1、静态代理
①定义父类
public interface Image { void display(); }
②被代理类
public class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("Display: " + fileName); } private void loadFromDisk(String fileName) { System.out.println("Loading: " + fileName); } }
③代理类
public class ProxyImage implements Image { private RealImage realImage; private String fileName; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (Objects.isNull(realImage)) { realImage = new RealImage(fileName); } realImage.display(); } }
④测试
public class _Test { public static void main(String[] args) { Image image = new ProxyImage("test.jpg"); image.display(); } }
代理类本身持有被代理类的对象,从而实现代理
2、jdk动态代理
①定义父类
public interface Subject { Integer sellBooks(); String speak(); }
②被代理类
public class RealSubject implements Subject { @Override public Integer sellBooks() { System.out.println("卖书"); return 1; } @Override public String speak() { System.out.println("说话"); return "张三"; } }
③代理类书写(需要实现InvocationHandler接口)
public class MyInvocationHandler implements InvocationHandler { private Subject realSubject; public MyInvocationHandler(Subject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用代理类"); if ("sellBooks".equals(method.getName())) { int invoke = (int) method.invoke(realSubject, args); System.out.println("调用卖书方法"); return invoke; } else { String invoke = (String) method.invoke(realSubject, args); System.out.println("调用说话方法"); return invoke; } } }
④测试
public class _Test { public static void main(String[] args) { Subject realSubject = new RealSubject(); MyInvocationHandler invocationHandler = new MyInvocationHandler(realSubject); Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, invocationHandler); proxyClass.sellBooks(); proxyClass.speak(); } }
动态的生成代理对象(继承自Proxy,实现Subject接口)
3、cnlib动态代理
①被代理类
public class Engineer { /** * 可以被代理 */ public void eat() { System.out.println("工程师正在吃饭"); } /** * final 方法不会被生成的字类覆盖 */ public final void work() { System.out.println("工程师正在工作"); } /** * private 方法不会被生成的字类覆盖 */ private void play() { System.out.println("this engineer is playing game"); } }
②cglib代理类编写
public class CglibProxy implements MethodInterceptor { private Object target; public CglibProxy(Object target) { this.target = target; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("### before invocation"); Object invoke = method.invoke(target, objects); System.out.println("### after invocation"); return invoke; } public static Object getProxy(Object target) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new CglibProxy(target)); return enhancer.create(); } }
③测试
public class _Test { public static void main(String[] args) { Engineer engineer = (Engineer) CglibProxy.getProxy(new Engineer()); engineer.eat(); } }
使用cglib需要引入相关依赖包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.10</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.2.10</version> </dependency>