• 设计模式之代理模式(十一)


    目录

    1. 静态代理

    2. 动态代理

     3. Cglib代理


    代理模式:为一个对象提供一个替身,以控制对这个对象的访问。好处就是可以用来增强。

    被代理的对象可以是 远程对象创建开销大的对象 或者 需要安全控制的对象。

    可以分为三类

    • 静态代理
    • 动态代理(JDK代理,接口代理)
    • Cglib代理(属于动态代理,在内存动态的创建对象,而不需要实现接口)

    示意图

     

    1. 静态代理

    目标对象与代理对象都要实现同一个接口或者继承相同父类。

    代码实现:

    1. public interface ITeacherDao {
    2. String teach();
    3. }
    4. public class TeacherDao implements ITeacherDao{
    5. private String name;
    6. public TeacherDao(String name) {
    7. this.name = name;
    8. }
    9. @Override
    10. public String teach() {
    11. System.out.println(name + "老师正在讲课。。。");
    12. return name;
    13. }
    14. }
    15. public class TeacherDaoProxy implements ITeacherDao{
    16. private ITeacherDao teacherDao;
    17. public TeacherDaoProxy(ITeacherDao teacherDao) {
    18. this.teacherDao = teacherDao;
    19. }
    20. @Override
    21. public String teach() {
    22. System.out.println("开始静态代理。。。,可以进行增强");
    23. String name = teacherDao.teach();
    24. System.out.println("结束静态代理。。。");
    25. return name;
    26. }
    27. }

    Client:

    1. public class Client {
    2. public static void main(String[] args) {
    3. ITeacherDao target = new TeacherDao("ksj");
    4. TeacherDaoProxy proxy = new TeacherDaoProxy(target);
    5. String teach = proxy.teach();
    6. System.out.println(teach);
    7. }
    8. }

     

    2. 动态代理

     

    静态代理缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类 ,一旦接口增加方法,目标对象与代理对象都要维护。

    这就要用到动态代理了,动态的在内存中构建代理对象,只需要目标对象实现接口。利用JDK的Api来实现。

    java.lang.reflect.Proxy里面的
    newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
    • ClassLoader loader:目标对象的类加载器。
    • Class[] interfaces: 目标对象实现的接口数组。
    • InvocationHandler h:事件处理器,里面利用反射调用方法。

    接口和目标类与上面静态代理相同,下面直接写代理工厂类

    1. public class ProxyFactory {
    2. private final Object target;
    3. public ProxyFactory(Object target){
    4. this.target = target;
    5. }
    6. public Object getProxyInstance() {
    7. return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    8. target.getClass().getInterfaces(),
    9. new InvocationHandler() {
    10. @Override
    11. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    12. System.out.println("JDK代理开始");
    13. Object returnVal = method.invoke(target, args);
    14. System.out.println("JDK代理结束");
    15. return returnVal;
    16. }
    17. });
    18. }
    19. }
    1. public class Client {
    2. public static void main(String[] args) {
    3. ITeacherDao target = new TeacherDao("ksj");
    4. System.out.println("target=" + target.getClass());
    5. ProxyFactory proxyFactory = new ProxyFactory(target);
    6. ITeacherDao proxyInstance = (ITeacherDao) proxyFactory.getProxyInstance();
    7. // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
    8. System.out.println("proxyInstance=" + proxyInstance.getClass());
    9. String name = proxyInstance.teach();
    10. System.out.println(name);
    11. }
    12. }

     3. Cglib代理

    Cglib 代理也叫作子类代理,属于动态代理。相比较静态代理和JDK代理,Cglib代理不需要实现接口。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接 口. 它广泛的被许多 AOP 的框架使用 , 例如 Spring AOP ,实现方法拦截。 
    • 目标对象需要实现接口,用JDK代理
    • 目标对象不需要实现接口,用Cglib代理
    简单来说就是实现MethodIterceptor接口,实现 intercept接口来实现代理。

    代码实现:

     

    1. public class TeacherDao {
    2. public String teach() {
    3. System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
    4. return "hello";
    5. }
    6. }
    7. public class ProxyFactory implements MethodInterceptor {
    8. //维护一个目标对象
    9. private Object target;
    10. //构造器,传入一个被代理的对象
    11. public ProxyFactory(Object target) {
    12. this.target = target;
    13. }
    14. //返回一个代理对象: 是 target 对象的代理对象
    15. public Object getProxyInstance() {
    16. //1. 创建一个工具类
    17. Enhancer enhancer = new Enhancer();
    18. //2. 设置父类
    19. enhancer.setSuperclass(target.getClass());
    20. //3. 设置回调函数
    21. enhancer.setCallback(this);
    22. //4. 创建子类对象,即代理对象
    23. return enhancer.create();
    24. }
    25. //重写 intercept 方法,会调用目标对象的方法
    26. @Override
    27. public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
    28. System.out.println("Cglib代理模式 ~~ 开始");
    29. Object returnVal = method.invoke(target, args);
    30. System.out.println("Cglib代理模式 ~~ 提交");
    31. return returnVal;
    32. }
    33. }
    34. public class Client {
    35. public static void main(String[] args) {
    36. //创建目标对象
    37. TeacherDao target = new TeacherDao();
    38. //获取到代理对象,并且将目标对象传递给代理对象
    39. TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
    40. //执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
    41. String res = proxyInstance.teach();
    42. System.out.println("res=" + res);
    43. }
    44. }

    还有其他代理变体:

    • 防火墙代理
    • 缓存代理
    • 远程代理
    • 同步代理等 
  • 相关阅读:
    SSM整合redis及redis的注解式开发和解决Redis缓存问题
    Qt --- Day01
    架构思考(四)
    「区块链+数字身份」:DID 身份认证的新战场
    CentOS 7 上安装 Oracle 11g 数据库
    纯css实现边界检测小球动画
    Azure AD(六)添加自定义域名
    远程桌面访问MATLAB 2018B,提示License Manger Error -103,终极解决方案
    Jetson Xavier NX 试玩 (二)
    JavaScript(一)基本语法概念
  • 原文地址:https://blog.csdn.net/weixin_45734473/article/details/127999053