代理模式学习笔记

代理模式(Proxy Pattern)

是指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。
使用代理模式主要有两个目的:一保护目标对象,二增强目标对象
事务代理、非侵入式日志监听等,这些都是代理模式的实际体现。

静态代理

概述

一个类要完成的事情交给另一个类去做,以快递举例,快递送到家本来需要自己去取,现在由快递员送到家

首先编写顶层接口,里面有取快递方法

public interface GetPackage {
    void getPackage();
}

定义两个类,我和快递员,都具有取快递方法

//我
public class Myself implements GetPackage {

    private String myName = "我";

    @Override
    public void getPackage() {
        System.out.println(myName + "得到了快递");
    }
}
//快递员
public class Postman implements GetPackage {
	
    private Myself me;
	//创建时,需要将被代理的类传入
    Postman(Myself me){
        this.me = me;
    }

    @Override
    public void getPackage() {
        this.me.getPackage();
    }
}

调用

public static void main(String[] args) {
        Postman postman = new Postman(new Myself());
        postman.getPackage();
}

输出结果:
在这里插入图片描述

应用场景

实际生产时,我们可能进行了分库分表,那么在实际操作时,我们使用代理对象的方法去处理分表分库的策略,而被代理的对象,只完成订单的插入

强制代理

防止其被他的类代理,保证代理的类是唯一的,可以采用强制代理,将初始化的过程隐藏在内部,不接受从外部传入

顶层接口中加入获取代理对象的方法

public interface GetPackage {
    
	//取快递
	void getPackage();

	//获取代理对象
	GetPackage getProxy();
}

继承该方法

//我
public class Myself implements GetPackage {

    private String myName = "我";

	private Postman postman;
	
    @Override
    public void getPackage() {
		if(postman == null){
			System.out.println("未创建代理对象");
			return;
		}
        System.out.println(myName + "得到了快递");
    }
    
    //只有执行该方法时,this.postman对象不为null,才可成功调用getPackage()方法打印想要的结果
    @Override
    public GetPackage getProxy() {
        this.postman = new Postman(this);
        return this.postman;
    }
}

//快递员
public class Postman implements GetPackage {
	
    private Myself me;
	//创建时,需要将被代理的类传入
    Postman(Myself me){
        this.me = me;
    }

    @Override
    public void getPackage() {
        this.me.getPackage();
    }
}

主方法未调用getProxy()时,

public static void main(String[] args) {
        Postman postman = new Postman(new Myself());
        postman.getPackage();
}

运行结果:
在这里插入图片描述
主方法调用了getProxy()时,

public static void main(String[] args) {
	GetPackage me = new Myself();
    GetPackage postman = me.getProxy();
    postman.getPackage();
}

运行结果:
在这里插入图片描述

动态代理

静态代理可以完成解耦的需要,但是静态代理类的代码维护较为复杂,一旦接口或父类的方法改变,则代理类的代码也需要随之修改,所以在实际开发时,我们通常采用动态代理

概述

动态代理技术,是在内存中生成代理对象的一种技术,整个代理过程在内存中进行,不需要手写代理类的代码,不存在类编译的过程,而是在运行期由JVM创建一个对象供我们使用

基于JDK(接口)的动态代理

JDK自带的代理技术,需要使用一个静态方法来创建代理对象,要求被代理对象必须实现接口,生成的代理对象和原对象都实现相同的接口,是兄弟关系

public interface GetPackage {
    void getPackage();
}

//我
public class Myself implements GetPackage {

    private String myName = "我";

    @Override
    public void getPackage() {
        System.out.println(myName + "得到了快递");
    }
}

动态代理类:

public class ProxyHandler implements InvocationHandler {
    
    Object object = null;

    //代理的目标
    public ProxyHandler (Object object) {
        this.object = object;
    }

    //调用目标方法
    //在方法中,编写对被代理对象方法的增强或扩展逻辑
    //在调用代理对象的方法时,该方法会被调用
    //参数1:代理类对象的一个引用,即Proxy.newProxyInstance()方法的返回值
    //参数2:被代理对象的方法
    //参数3:被代理对象方法的参数
    //method.invoke(object,args)方法 参数1:被代理对象实例 参数2:方法参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.object,args);
    }
}

public class MyProxy {
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
        T newProxyInstance = (T) Proxy.newProxyInstance(loader,interfaces, h);
        return newProxyInstance;
    }
}

开始取快递

    public static void main(String[] args) throws Throwable{
        GetPackage me = new Myself();
        ClassLoader cl = me.getClass().getClassLoader();

		//newProxyInstance(
		//			ClassLoader loader,
        //          Class<?>[] interfaces,
        //          InvocationHandler h
        //	)
        //参数1:被代理对象的类加载器 参数2:被代理对象实现的接口 
        //参数3:这个参数是一个接口,里面有唯一的invoke()方法,该方法会在代理类对象调用方法时执行,
        //我们在重写该invoke方式时,对原方法进行扩展或增强
        GetPackage proxy = MyProxy.newProxyInstance(cl,new Class[] {GetPackage .class}, new ProxyHandler (me));
        proxy.getPackage();
    }

输出结果:
在这里插入图片描述
可以看到,通过这种方式,我们不需要创建固定的代理类Postman对象,而是在使用时,通过proxy去动态的代理对象

基于CGLIB(父类)的动态代理

第三方动态代理技术,也是使用一个静态方法来创建对象,它基于目标类生成一个子类,所以要求目标类不能是最终类,不能被final修饰

    public static void main(String[] args) throws Throwable{
        GetPackage me = new Myself();
        //参数1:Class type 目标类的字节码对象
        //参数2:Callback callback 回调方法,Callback是一个起定义名称作用的接口,
        //一般我们使用它的子接口MethodIntercepter,其中有唯一方法intercept()
       	GetPackage proxy = Enhancer.create(me.getClass() ,new Intercepter({
			//参数1:代理类对象引用Enhancer.create()方法的返回值
			//参数2:目标类方法
			//参数3:方法参数
			//参数4:方法的代理对象
			@Override
			public Object intercept(
				Object proxy, 
				Method method, 
				Object[] args, 
				MethodProxy methodProxy
			) throws Exception{
				return method.invoke(me,args);
			}
		}));
		proxy.getPackage();
    }

执行结果:
在这里插入图片描述
基于父类的动态代理,在内存中生成了一个对象,该对象继承了原对象,是原对象的子类,可以用父类对象的引用接收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值