• java中的代理模式


    一、什么是代理模式

    定义: 给目标对象提供一个代理对象,并且由代理对象控制对目标对象的引用。
    目的:

    ①:功能增强:通过代理业务对原有业务进行增强
    ②:控制访问:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性

    二、相关概念

    目标类:原对象,我们需要代理对象控制他的访问,拓展其功能。
    代理类:代理模式产生的对象,是原对象“替身”,已经在原有基础上修改逻辑
    
    • 1
    • 2

    在这里插入图片描述

    三、实现代理的三种方式

    (1).静态代理

    1.静态代理的特点

    ①:代理类是自己手动实现的,需要自己去创建一个类
    ②:代理类所代理的目标类是固定的

    2.利用接口实现静态代理

    静态代理逻辑图
    在这里插入图片描述
    关于接口的方式,我们在实现接口的时候,目标类和代理类都必须实现目标接口当中所实现的方法,从某种意义上代理类就可以帮我们实现目标类当中的方法,并且代理类还可以有自己的扩展方法。

    3.代码实现

    首先先定义接口

    public interface ByClothes {
    	void clothes(String size);
    }
    
    • 1
    • 2
    • 3

    定义目标对象

    public class ClothesFactory implements ByClothes {
    	@Override
    	public void clothes(String size) {
    		System.out.println("已经为您制作好了一整套size为"+size+"的衣服。。。。。。。。");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    制造代理对象

    public class proxy implements ByClothes {
    
    	
    	//被包含的真是对象
    	public ClothesFactory factory = new ClotheFactory;
    	// 对功能的增强
    	@Override
    	public void clothes(String size) {
    		FrontService();
    		factory.clothes(size);
    		endService();
    	}
    	
    	//前置服务
    	public void FrontService() {
    		System.out.println("根据您的需求进行市场调研");
    	}
    
    	//前置服务
    	public void endService() {
    		System.out.println("为您提供一条龙的包办服务");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    制造测试类------买衣服的人

    public class Test {
    	public static void main(String[] args) {
    		Proxy proxy = new Proxy();
    		proxy.clothes("xxL");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.静态代理存在的问题

    ①:当目标类曾多时,代理类也需要增多,导致代理类的关系不便。
    ②:当接口当中的功能增多或者修改,都会影响实体类,违反开闭原则(程序对访问开放,对修改关闭)

    (2).JDK动态代理

    1.静态代理和动态代理的区别

    静态代理需要我们手动的去创建代理对象,动态代理则是采用jdk提供的方法创建代理对象

    2.JDK动态代理的实现

    使用java反射包当中的类和接口实现动态代理的功能

    3.JDK动态代理逻辑图

    在这里插入图片描述

    4.jdk动态代理

    新建接口

    public interface ByShoot {
    	void byShoot(String size);
    }
    
    • 1
    • 2
    • 3

    新建工厂

    public class ShootFactory implements ByShoot{
    
    	@Override
    	public void byShoot(String size) {
    		System.out.println("已经为您生产出了尺码为"+size+"的鞋子");
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代理类

    public class LisiFactory implements InvocationHandler {
    
    	// 被代理的对象
    	private Object factory ;
       public DyProxy(Object factory) {
    		 this.factory = factory;
    	} 
        
        
        //三个参数的讲解
        //1.Object:jdk创建的代理类,无需赋值
        //2.Method:目标类当中的方法,jdk提供,无需赋值
        //3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		FrontService();
    		method.invoke(factory, args);  //这里的invoke(目标对象,方法参数)
    		endService();
    		return null;
    	}
    
    	// 前置服务
    	public void FrontService() {
    		System.out.println("根据您的需求进行市场调研");
    	}
    
    	// 后置服务
    	public void endService() {
    		System.out.println("为您提供一条龙的包办服务");
    	}
     
     	//该方法并不是固定的,但是内部的Proxy类的创建是核心
    	public Object getProxyInstance() {
    		// TODO Auto-generated method stub
    		return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    新建测试类

    public class Test {
    	public static void main(String[] args) {
    		ClothesFactory clothesFactory = new ClothesFactory();
        	ByClothes clothes = (ByClothes) new 动态代理类(clothesFactory).hhh(); // 1.代理谁  //2.接口是什么
        	clothes.clothes("XXXL");
        	ShootFactory shootFactory = new ShootFactory();
        	ByShoot shoot = (ByShoot) new 动态代理类(shootFactory).hhh();
        	shoot.shoot("1000");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.JDK代理类实现细节

    ①:InvocationHandler接口:里边只有一个invoke()方法
    invoke()方法:表示我们要求代理对象要完成的功能
    1).调用并执行目标的方法
    2).功能增强,在目标对象调用时增强其功能
    ②:Proxy类:核心对象,其目的是创建道理对象
    以前我们创建对象是new构造器,现在我们使用Proxy类的方法,代理new的使用
    newProxyInstance()方法的作用是创建代理对象,其返回值就是代理对象

    //ClassLoader loader:类的加载器,复杂向内存当中加载对象,使用反射的方式获取
    // Class[] interfaces:目标对象实现的接口,也是反射获取
    //InvocationHandler h:代理类需要完成的功能
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3).cglib动态代理

    1.jdk动态代理的问题

    使用jdk动态代理存在一个问题,jdk提供的动态代理只能为拥有接口的类进行动态代理,但是对于没有实现接口的类,则没有办法进行动态代理。

    2.什么是cglib动态代理

    cglib是是第三方的工具库。其原理是继承,cglib通过继承目标类,创建他的子类,在子类当中重写父类的相关方法,实现功能的增强。

    3.cglib基本结构

    下图所示,代理类去继承目标类,每次调用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类的该方法的逻辑。
    在这里插入图片描述

    4.cglib实现动态代理的原理

    1.生成一个空的字节码对象
    2.通过字节码对象生成目标类对象的子类 进行增强
    3.实现拦截器,通过连接器实现代理的类方法
    4.创建代理对象
    
    • 1
    • 2
    • 3
    • 4

    5.代码实现

    CGLib动态代理中提供了一个类Enhance,需要用它生成一个空的字节码对象,所以我们需要导入外部的jar包依赖。

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    目标类

    /**
     * 目标类
     */
    public class ClothesFactory {
        public void clothes(String size) {
            System.out.println("已经为您制作好了一整套size为"+size+"的衣服。。。。。。。。");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    拦截器

    
    /**
     * 实现拦截器,通过连接器实现代理的类方法
     */
    public class MyMethodInterceptor implements MethodInterceptor {
        /**
         *
         * @param o   代理对象
         * @param method 目标对象中的方法
         * @param objects 目标对象中方法的参数
         * @param methodProxy 代理对象中代理方法对象
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("前置增强");
            methodProxy.invokeSuper(o,objects);  // 动态的回调父类当中的方法
            System.out.println("后置增强");
            return o;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    代理类

    /**
     * 代理类
     */
    public class CglibProxy  {
        
        public static Object createProxy(String path) throws ClassNotFoundException {
            Enhancer enhancer = new Enhancer();  //生成空的字节码对象
            enhancer.setSuperclass(Class.forName(path)); //通过字节码对象生成目标类对象的子类 进行增强
            enhancer.setCallback(new MyMethodInterceptor()); //实现拦截器,通过连接器实现代理的类方法
            Object o = enhancer.create();//创建代理对象
            return o;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试

    public class Test {
        public static void main(String[] args) throws ClassNotFoundException {
            //生成代理对象
            ClothesFactory proxy = (ClothesFactory) CglibProxy.createProxy("com.qcby.ClothesFactory");
            //方法调用
            proxy.clothes("xxxL");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    【排序算法】Leetcode刷题心得
    CUDA编程基础:了解malloc以及堆、栈的基本概念,malloc声明的优点
    时间同步产品(NTP北斗时钟服务器)如何完成网络同步的?
    Springboot整合轻量级反爬虫组件kk-anti-reptile
    18.3 【Linux】登录文件的轮替(logrotate)
    stream()流的一些常用方法
    前端工作总结113-点击按钮报错--bug修复--直接写接口里面
    【Druid 未授权访问漏洞】解决办法
    Linux目录操作
    Hbase 笔记
  • 原文地址:https://blog.csdn.net/weixin_39038328/article/details/136666777