一、定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式分为静态代理、动态代理。动态代理又分为JDK动态代理和CGLIB动态代理。
二、优点及缺点
静态代理优点:
1、客户端不必知道实现类(委托类)的内部方法实现,只需要调用代理类即可。
缺点:
1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。但这样出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也要实现这个方法。这显然增加了代码的复杂度。
2、代理对象只服务于一种类型的对象,如果要服务多类型的对象,那就要对每种对象都进行代理,程序过于繁琐。
动态代理优点:
1、减少编程的工作量:无需为每个方法都写一个代理方法,无需为每一个类都书写一个代理类。
2、系统扩展性和维护性增强,修改方便,直接修改代理类。
三、代码实现:
1、静态代理
接口类:
package com.example.demo.sjms.jingtaidailimoshi; /** * @Author: caesar * @Date:2020年10月15日 18:10:25 * @Description: 买车接口 */ public interface ByCar { public void payForTheCar(int money); }
实现类:
package com.example.demo.sjms.jingtaidailimoshi; import lombok.Data; /** * @Author: caesar * @Date:2020年10月15日 18:10:57 * @Description: 买车的实现类 */ @Data public class Customer implements ByCar{ private int money; @Override public void payForTheCar(int money) { System.out.println("使用"+money+"元,买了一辆车"); } }
代理类:
package com.example.demo.sjms.jingtaidailimoshi; /** * @Author: caesar * @Date:2020年10月15日 19:10:23 * @Description: 代理类,需要在调用买车方法之前,首先判断这个人的钱是否够用 */ public class CarProxy implements ByCar { // 最少钱数 private final int MIN_MONEY = 100000; // 引入委托对象 private Customer customer; public CarProxy(Customer customer){ this.customer = customer; } // 代理方法 @Override public void payForTheCar(int money) { if(customer.getMoney() < MIN_MONEY){ System.out.println("钱数不够无法购买,还缺"+ (MIN_MONEY - money)+"元"); return; } customer.payForTheCar(money); } }
测试类:
package com.example.demo.sjms.jingtaidailimoshi; /** * @Author: caesar * @Date:2020年10月15日 19:10:33 * @Description: 测试类 */ public class Test { public static void main(String[] args) { CarProxy carProxy = new CarProxy(new Customer()); carProxy.payForTheCar(1000); } }
2、动态代理
(1)、JDK动态代理(基于实现相同的接口)
JDK动态代理是基于反射机制。通过java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。最主要的特点就是,代理类必须和被代理类实现相同的接口,也就是说被代理类一定要有实现的接口,否则不可以使用JDK动态代理。
实体类和接口类不再多写和上面相同
动态代理类:
package com.example.demo.sjms.JDKdongtaidaili; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @Author: caesar * @Date:2020年10月15日 19:10:15 * @Description: JDK动态代理 */ public class JDKProxy<T>{ private T target; public JDKProxy(T target){ this.target = target; } /*** * @Author: caesar * @Date:2020年10月15日 19:10:26 * @Description: 动态代理方法 * @Param: * @Return: */ public T getProxy(){ return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法执行之前执行。。。。。。"); Object object = method.invoke(target,args); System.out.println("方法执行之后执行。。。。。。"); return object; } }); } }
测试类:
package com.example.demo.sjms.JDKdongtaidaili; /** * @Author: caesar * @Date:2020年10月15日 19:10:37 * @Description: 测试类 */ public class Test { public static void main(String[] args) { Person user = new User(); JDKProxy<Person> jdkProxy = new JDKProxy<Person>(user); Person proxyUser = jdkProxy.getProxy(); proxyUser.say(); } }
(2)、CGLIB动态代理类(继承)
利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。cglib代理的类,无需强制实现接口,其生成的代理类 是 被代理类的子类,并且重写的被代理类的方法,只需引包即可。
引入的jar包:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency>
委派类也不再多写,和上面的相同
CGLIB代理类:
package com.example.demo.sjms.CGLIBdongtaidaili; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @Author: caesar * @Date:2020年10月15日 19:10:15 * @Description: CGLIB动态代理 */ public class CGLIBProxy<T>{ public T getCGLIBProxy(Class<T> tClass){ return (T) Enhancer.create(tClass, new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("方法前执行。。。。。。"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("方法后执行。。。。。。"); return result; } }); } }
测试类:
package com.example.demo.sjms.CGLIBdongtaidaili; /** * @Author: caesar * @Date:2020年10月15日 19:10:37 * @Description: 测试类 */ public class Test { public static void main(String[] args) { CGLIBProxy<User> cglibProxy = new CGLIBProxy<User>(); User proxyUser = cglibProxy.getCGLIBProxy(User.class); proxyUser.say(); } }
四、源码级别
springAOP就是动态代理:这是本人的有关博客位置:https://www.cnblogs.com/mcjhcnblogs/category/1791152.html
五、总结
注释:原来博客中书写过有关代理模式的详解地址如下:可能代码不如这个整洁,但是总结的很详细:https://www.cnblogs.com/mcjhcnblogs/p/13174171.html