代理模式

一、什么是代理模式

  为其他对象提供一种代理以控制对这个对象的访问

  例如,买火车票不一定在火车站买,也可以去代售点

二、如何编写代理模式

2.1 兄弟模式的静态代理

package com.shanda.test1;

public interface SellPiao {
	void maipiao();
}

package com.shanda.test1;

public class HuoCheZhan implements SellPiao{

	@Override
	public void maipiao() {
		System.out.println("买票");
	}

}

package com.shanda.test1;

public class DaiShouDian implements SellPiao{
	private HuoCheZhan hcz=null;
	public DaiShouDian(HuoCheZhan hcz) {
		this.hcz=hcz;
	}
	@Override
	public void maipiao() {
		hcz.maipiao();
	}
	
}

package com.shanda.test1;

public class TestMain {

	public static void main(String[] args) {
		HuoCheZhan hcz=new HuoCheZhan();
		hcz.maipiao();
		DaiShouDian dsd=new DaiShouDian(hcz);
		dsd.maipiao();
	}

}

运行结果:
在这里插入图片描述
  上面的实例体现了静态处理【兄弟模式的静态代理】

2.2 父子模式的静态代理

package com.shanda.test2;

public class HuoCheZhan {
	public void maipiao() {
		System.out.println("买票");
	}

}

package com.shanda.test2;

public class DaiShouDian extends HuoCheZhan{
	public void maipiao() {
		super.maipiao();
	}
}

package com.shanda.test2;

public class TestMain {

	public static void main(String[] args) {
		HuoCheZhan hcz=new HuoCheZhan();
		hcz.maipiao();
		DaiShouDian dsd=new DaiShouDian();
		dsd.maipiao();
	}

}

运行结果:

在这里插入图片描述
  上面的这个实例体现了静态代理【符字模式的静态代理】

  静态代理的缺点需要手动创建子类,当需要被代理语言较多的时候,我们的工作量变大了。

  由于静态代理的上述缺点,所以我们需要一个专门生产代理对象的类。

  动态代理 —> 通过 java.lang.reflect Class Proxy 类来创建代理类对象。

有两种方式

2.3 JDK动态代理

  动态代理相比于静态代理,动态代理的代理类是在动态生成的,也就是jvm通过反射获取代码生成代理类,所以用户并不能决定代理角色和真实角色之间的联系,而是由程序运行时候决定的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

  动态代理实现的三步走:
  1.实现InvocationHandler接口,创建自己的调用处理器 。
  2.给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类 。
  3.执行真实角色具体任务。

  要想创建处理器必须实现InvocationHandler接口,之后通过类装载器创建代理类。每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

  Object invoke(Object proxy, Method method, Object[] args) throws   Throwable
  proxy:指代我们所代理的那个真实对象
  method:指代的是我们所要调用真实对象的某个方法的Method对象
  args:指代的是调用真实对象某个方法时接受的参数

我们依旧要创建抽象角色和真实角色类

package com.shanda.test3;

public interface MaiPiaoInterface {
	void maipiao();
}

package com.shanda.test3;

public class HuoCheZhan implements MaiPiaoInterface{

	@Override
	public void maipiao() {
		System.out.println("火车站买票");
	}

}

package com.shanda.test3;

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

public class CreateDaiShouDianObject implements InvocationHandler{
	//定义目标对象
	private Object targetObject;
	public CreateDaiShouDianObject(Object targetObject) {
		this.targetObject=targetObject;
	}
	
	//得到代理对象
	public Object getProxy() {
		//参数1--ClassLoader loader
		//参数2--Class<?>[] interfaces
		//参数3--InvocationHandler h
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
	}
	/**
	 * proxy:指代我们所代理的那个真实对象
		method:指代的是我们所要调用真实对象的某个方法的Method对象
		args:指代的是调用真实对象某个方法时接受的参数
	 */

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		return method.invoke(targetObject, args);
	}
}

package com.shanda.test3;

public class TestMain {

	public static void main(String[] args) {
		HuoCheZhan hcz=new HuoCheZhan();
		hcz.maipiao();
		CreateDaiShouDianObject cdlo=new CreateDaiShouDianObject(hcz);
		MaiPiaoInterface daishoudian=(MaiPiaoInterface)cdlo.getProxy();
		daishoudian.maipiao();
	}

}

运行结果:

在这里插入图片描述

  看上去实现很简单,我们只需要实现接口,调用其中的方法就可以实现动态代理。
  通过newProxyInstance方法获取代理类实例,而后我们便可以通过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法。
  注意:JDK动态代理只能处理有接口实现关系的java类

2.4 Cglib动态代理

  cglib是一个强大的高性能的代码生成包,广泛的被许多AOP的框架使用,它的开源地址在https://github.com/cglib/cglib

导包过程:
  (1)在项目工程下右键 —> new —> Folder 创建一个文件夹命名为lib
  (2)将开发包复制到lib文件夹下
  (3)在项目工程下右键 —> Build Path —> Configure Buile Path… —> Libraries —> Add JARs… 找到项目 lib 文件夹下的开发包 —> OK —> Apply —> Apply and Close

  通过它实现动态代理,主要用到import net.sf.cglib.proxy包下的MethodInterceptor、MethodProxy和Enhancer类
  (1)、MethodInterceptor
  MethodInterceptor类是方法拦截器,代理类实例的方法被调用时会回调MethodInterceptor的intercept()方法拦截,用来实现自己的代理逻辑,类似于jdk动态代理的InvocationHandler接口
  (2)、MethodProxy
  MethodProxy是intercept()方法中的第四个参数的类型,它是实际类方法的代理引用,使用methodProxy比使用jdk自身的method在效率上会有提升
  (3)、Enhancer
  Enhancer用来动态创建实际类子类的代理类实例,setSuperclass()方法设置实际类为父类,setCallback()方法建立方法回调,create()方法创建一个代理类实例

package com.shanda.test4;

public interface MaiPiaoInterface {
	void maipiao();
}

package com.shanda.test4;

public class HuoCheZhan implements MaiPiaoInterface{

	@Override
	public void maipiao() {
		System.out.println("火车站买票");
	}

}

package com.shanda.test4;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CreateDaiShouDianObject implements MethodInterceptor{
	//定义目标对象
	private Object targetObject;
	public CreateDaiShouDianObject(Object targetObject) {
		this.targetObject=targetObject;
	}
	//创建代理对象
	public Object getProxy() {
		Enhancer enhancer=new Enhancer();
		enhancer.setSuperclass(targetObject.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}
	@Override
	public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
		// TODO Auto-generated method stub
		return methodProxy.invokeSuper(proxy, params);
	}
	

}

package com.shanda.test4;

public class TestMain {

	public static void main(String[] args) {
		HuoCheZhan hcz=new HuoCheZhan();
		hcz.maipiao();
		CreateDaiShouDianObject cdlo=new CreateDaiShouDianObject(hcz);
		HuoCheZhan daishoudian=(HuoCheZhan)cdlo.getProxy();
		daishoudian.maipiao();
	}

}

在这里插入图片描述
比较
  1. 静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
手动创建一个与目标类相同接口的子类,包装目标类。

  2. JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;【兄弟模式】
通过jdk提供的反射包中Proxy这个类,动态的创建一个与目标类实现相同接口的子类对象,包装目标。

  3. CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。【父子模式】
通过CGlib提供的Enhancer这个类,动态的创建一个目标类的子类对象,包装目标类。

静态代理JDK动态代理CGlib动态代理
手动创建代理类动态生成代理类对象动态生成代理类对象
jdk提供的反射包中Proxy这个类CGlib提供的Enhancer这个类
只能为实现过接口的Java类创建代理对象为任何Java类创建代理对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值