Java基础相关 | 静态/动态代理

Java基础相关 | 静态/动态代理

说起代理、代购、中介、换ip、商家等等,都是生活中的代理的例子

比如有一家X国的大学,可以对全世界招生。留学中介(代理)
留学中介(代理):帮助这家X国的学校招生,中介是学校的代理,中介是代替学校完成招生功能。


代理特点:

  1. 中介和代理他们要做的事情是一致的:招生。
  2. 中介是学校代理,学校是目标。
  3. 家长—中介(学校介绍,办入学手续)----X国学校。
  4. 中介是代理,不能白干活,需要收取费用。
  5. 代理不让你访问到目标。

为什么要找代理/中介?

  1. 中介是专业的,方便
  2. 家长现在不能自己去找学校。家长没有能力访问学校。或者美国学校不接收个人来访。
  3. 买东西都是商家卖,商家是某个商品的代理,你个人买东西,肯定不会让你接触到厂家的。

在开发中也会有这样的情况,你有a类,本来是调用c类的方法,完成某个功能

但是c不让a调用:
a 不能调用c的方法。
解决方法: 在a和c直接创建一个b代理,c让b访问。
a --> 访问b --> 访问c
实际的例子:登录,注册有验证码,验证码是手机短信。中国移动,联通或者旗下的子机构才能发短信。

在这里插入图片描述


使用代理模式的作用

  1. 功能增强:在你原有的功能上,增加了额外的功能。新增加的功能,叫做功能增强。
  2. 控制访问:代理类不让你访问目标,例如商家不让用户访问厂家。

1. 静态代理

  1. 代理类是自己手工实现的,自己创建一个java类,表示代理类
  2. 同时你所要代理的目标类是确定的。

优点:

  1. 实现简单
  2. 容易理解。

缺点:
当目标类和代理类比较多的时候,有如下缺点:

  1. 目标类增加了,代理类也可能成倍的增加,导致代理类数量过多;
  2. 接口中的功能增加了,或者修改了,会影响众多的实现类,厂家类、代理类都需要修改,耦合性极强!

1.1 实例

模拟一个用户购买u盘的行为

  1. 用户是客户端类
  2. 商家:代理,代理某个品牌的u盘
  3. 厂家:目标类.

三者的关系:用户(客户端)–> 商家(代理)–> 厂家(目标)工商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。


实现步骤:

  1. 创建一个接口:定义卖u盘的方法,表示你的厂家和商家做的事情
  2. 创建厂家类:实现1步骤的接口
  3. 创建商家:就是代理,也需要实现1步骤中的接口
  4. 创建客户端类:调用商家的方法买一个u盘

代理类完成的功能:

  1. 目标类中的方法调用
  2. 功能增强

落地实现:
1.接口:

public interface UsbSell{
	float sell(int amount);
}

2.厂家类:

public class UsbKingFactory implements UsbSell{
	@Override
	public float sell(int amount){
		return 85.0f;
	}
}
public class TaoBao implements UsbSell{
	private UsbKingFactory factory = new UsbKingFactory;

	@Override
	public float sell(int amount){
		float price = factory.sell(amount);
		price += 25;
		System.out.println("送您一个优惠券下次可以用!");
		return price;
	}
}

Main主启动类实现:
在这里插入图片描述
InvocationHandler接口的实现类:
在这里插入图片描述
二者之间的关系:
在这里插入图片描述


2. 动态代理

2.1 什么是动态代理?

使用JDK反射机制,创建对象的能力,创建的是代理类对象,而不用创建类文件,也不用写JAVA文件。

动态: 在程序执行时,调用jdk提供的方法才能创建代理的对象。

注: jdk动态代理必须有接口,目标类必须实现接口;没实现接口需要使用CGlib动态代理;

2.2 动态代理能做什么?

可以在不改变原来目标方法的前提下,在代理中增强目标方法。

如调用其他人写好的文件(.class文件),但是功能还缺一点(如缺少print)可以通过动态代理实现,无需修改源文件;降低耦合性;

2.1 JDK动态代理

这是默认的生成代理方式
JDK动态代理通过反射实现,Method类表示方法,通过Method类可以执行多个方法。

JDK动态代理的实现:
在java.lang.reflect包中,有三个类:

  1. InvocationHandler:
    只有一个方法:invoke():表示对象要执行的功能代码,代理类的功能写在该方法中;

方法参数:
InvocationHandler(Object proxy, Method method, Object[] args)

  • proxy:jdk创建的代理对象,无需赋值;
  • method:目标类中的方法,jdk提供method对象的;
  • args:目标类中方法的参数,jdk提供的;

如何使用?

  • 创建类去实现InvokeHandler接口;
  • 重写invoke()方法;

  1. Method:表示目标类中的方法
    作用:
  • 通过Method可以执行某个目标类的方法,Method.invoke();
  • method.invoke(目标对象,方法的参数) 如:Object ret = method.invoke(service2,"李四");

说明: method.invoke()就是用来执行目标方法的,等同于静态代理中的向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell (amount); //厂家的价格。


  1. Proxy:核心的对象,创建代理对象,静态对象是通过new类的构造方法,但是proxy可以代替new;

方法: 静态方法newProxyInstance() (创建代理对象,等同于Taobao tb = new Taobao();)


参数: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvokeHandler h)

  • loader:目标对象的类加载器,一般获取方法:a.getClass().getClassLoader()
  • interfaces:目标对象实现的接口,通过反射获取
  • h:代理类要完成的功能(我们自己写的)
  • 返回值:返回自定义代理对象

落地实现:
目标接口:

public interface UsbSell{
	float sell(int amount);
}

目标类:

public class UsbKingFactory implements UsbSell{
	@Override 
	public float sell(int amount){
		System.out.println("目标类中执行sell方法!");
		return 85.5f;
	}
}

实现:

class MySellHandler{
	private Object target = null;

	public MySellHandler(Object target){
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
		Object res = null;
		res = method.invoke(target, args);
		
		price += 35;
		System.out.println("淘宝商家,返回优惠券!");
	}
}

定义Main方法:

public class MainShop{
	public static void main(String[] args){
		UsbSell factory  = new UsbKingFactory;
		InvocationHandler handler = new MySellHandler(factory);

		UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), handler);
	} 
}



2.2 CGLib动态代理

CGLib在这里只做简述: 它是通过asm字节码生成器生成被代理类的子类,效率没有反射快,而且被代理类不能被final修饰否则不能被继承。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值