Spring学习之——代理模式

Proxy代理模式

介绍

  1. 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

2. 组成

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

    抽象角色一般声明为接口,内部写真实角色的抽象方法。

    eg.有一个公共的歌手接口,有一个唱歌的方法

  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

    eg.有一个类叫做周杰伦,实现了歌手的接口

  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

    代理角色一般是来执行真实角色的方法以及自己所附加的方法。

    eg.有一个经纪人的类,他是来对接客户(实际调用者),他可以让周杰伦去唱歌,自己同时完成了面谈,签合同,订机票,收尾款等行为方法。

静态代理

1.抽象角色

java 复制代码
package com.by.proxy.StaticProxy;

public interface Star {
	/**
	 * 面谈
	 */
	void confer();
	/**
	 * 签合同
	 */
	void signContract();
	/**
	 * 订票
	 */
	void bookTicket();
	/**
	 * 唱歌
	 */
	void sing();
	/**
	 * 收钱
	 */
	void collectMoney();
}

2.真正角色(周杰伦)

java 复制代码
package com.by.proxy.StaticProxy;

public class RealStar implements Star {

	public void bookTicket() {

	}

	public void collectMoney() {

	}

	public void confer() {

	}

	public void signContract() {

	}

	public void sing() {
		System.out.println("RealStar(周杰伦本人).sing()");
	}
}

3.代理角色(经纪人)

java 复制代码
package com.by.proxy.StaticProxy;

public class ProxyStar implements Star {
	
	private Star star;
	
	public ProxyStar(Star star) {
		super();
		this.star = star;
	}

	public void bookTicket() {
		System.out.println("ProxyStar.bookTicket()");
	}

	public void collectMoney() {
		System.out.println("ProxyStar.collectMoney()");
	}

	public void confer() {
		System.out.println("ProxyStar.confer()");
	}

	public void signContract() {
		System.out.println("ProxyStar.signContract()");
	}

	public void sing() {
		star.sing();
	}
}

4.测试

java 复制代码
package com.by.proxy.StaticProxy;

public class Client {
	public static void main(String[] args) {
		Star proxy = new ProxyStar(new RealStar());
		
		proxy.confer();
		proxy.signContract();
		proxy.bookTicket();
		proxy.sing();
		
		proxy.collectMoney();
		
	}
}

5.静态代理的缺点

  1. 代理类和实现类实现了相同的接口,这样就出现了大量的代码重复。
  2. 代理对象只服务于一种类型的对象。如果要服务多类型的对象,例如代码是只为UserService类的访问提供了代理,但是还要为其他类如DeptService类提供代理的话,就需要我们再次添加代理DeptService的代理类。

jdk动态代理

1.抽象角色

java 复制代码
public interface Star {
    /**
     * 唱歌
     */
    void sing();
}

2.真正角色(周杰伦)

java 复制代码
package com.by.JdkProxy;

//真实角色(周杰伦)
public class RealStar implements Star {
    //优点:此时代码不再重复

    public void sing() {
        System.out.println("周杰伦:快使用双截棍,哼哼哈嘿....");

    }
}

3.代理角色(经纪人)

java 复制代码
package com.by.JdkProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理类工厂
public class ProxyFactory {

    //优点:此时可以代理任意类型的对象
    //真实角色(周杰伦)
    private Object realObj;

    public ProxyFactory(Object realObj) {
        this.realObj = realObj;
    }

    //获得代理对象
    public Object getProxyObject(){

        /**
         * Proxy:作用创建代理对象
         *      ClassLoader loader:类加载器
         *      Class<?>[] interfaces:真实角色实现的接口,根据接口生成代理类
         *      InvocationHandler h:增强的逻辑,即如何代理(宋吉吉要做的事)
         */
        return Proxy.newProxyInstance(
                realObj.getClass().getClassLoader(),
                realObj.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     *
                     * @param proxy:代理类,一般不用
                     * @param method:要调用的方法
                     * @param args:调用方法时的参数
                     * @return
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args)
                        											throws Throwable {

                        System.out.println("真正的方法执行前!");
                        System.out.println("面谈,签合同,预付款,订机票");

                        Object result = method.invoke(realObj, args);

                        System.out.println("真正的方法执行后!");
                        System.out.println("收尾款");

                        return result;
                    }
                }
        );
    }
}

4.测试

java 复制代码
public class Client {
    public static void main(String[] args) {
        //获得代理对象
        Star proxyObject = (Star) new ProxyFactory(new RealStar()).getProxyObject();
        System.out.println(proxyObject.getClass());//class com.sun.proxy.$Proxy0
        proxyObject.sing();
    }
}

Cglib动态代理

cglib与动态代理最大的区别就是:

  • 使用jdk动态代理的对象必须实现一个接口
  • 使用cglib代理的对象则无需实现接口

CGLIB是第三方提供的包,所以需要引入jar包的坐标:

xml 复制代码
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

1.真正角色

java 复制代码
package com.by.proxy.CglibProxy;

public class RealStar{

	public void sing() {
		System.out.println("RealStar(周杰伦本人).sing()");
	}
}

2.代理角色(经纪人)

java 复制代码
package com.by.proxy.CglibProxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

//代理工厂
public class ProxyFactory implements MethodInterceptor {

    //真实角色
    private Object realObj;

    public ProxyFactory(Object realObj) {
        this.realObj = realObj;
    }

    /**'
     * 获得子类代理对象
     * @return
     */
    public Object getProxyObject() {
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(realObj.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类代理对象
        return en.create();
    }
    /*
        在子类中调用父类的方法
            intercept方法参数说明:
                obj : 代理对象
                method : 真实对象中的方法的Method实例
                args : 实际参数
                methodProxy :代理对象中的方法的method实例
     */
    public Object intercept(Object obj, Method method, Object[] args, 
                            	MethodProxy methodProxy)throws Throwable {
        System.out.println("真正的方法执行前!");
        System.out.println("面谈,签合同,预付款,订机票");

        Object result = method.invoke(realObj, args);

        System.out.println("真正的方法执行后!");
        System.out.println("收尾款");
        return object;
    }
}

3.测试

java 复制代码
package com.by.proxy.CglibProxy;

//测试类
public class Client {
    public static void main(String[] args) {
        //获取代理对象
        RealStar proxyObject = 
            (RealStar) new ProxyFactory(new RealStar()).getProxyObject();
        proxyObject.sing();
    }
}

AOP中的代理

  1. 切点对应的是真实角色的方法
  2. 增强对应的是抽象角色,创建了真实角色的代理类,不仅执行了真实角色的方法,还加入了自己的方法(前置通知,后置通知,异常通知,环绕通知,最终通知)
相关推荐
执笔论英雄2 小时前
【大模型学习cuda】入们第一个例子-向量和
学习
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [drivers][input]input
linux·笔记·学习
Gary Studio5 小时前
rk芯片驱动编写
linux·学习
mango_mangojuice5 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习
lingggggaaaa5 小时前
安全工具篇&动态绕过&DumpLsass凭据&Certutil下载&变异替换&打乱源头特征
学习·安全·web安全·免杀对抗
PP东5 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
学电子她就能回来吗5 小时前
深度学习速成:损失函数与反向传播
人工智能·深度学习·学习·计算机视觉·github
AI视觉网奇7 小时前
ue 角色驱动衣服 绑定衣服
笔记·学习·ue5
张3蜂7 小时前
深入理解 Python 的 frozenset:为什么要有“不可变集合”?
前端·python·spring
Coder_Boy_8 小时前
基于Spring AI的分布式在线考试系统-事件处理架构实现方案
人工智能·spring boot·分布式·spring