关于“静态代理”与“动态代理”
一、什么是代理?
概念:
代理就是一个中间桥梁,生活中类似于中介。比如商家就是一个中介,顾客从商家那购买商品,商家从厂家那进购商品,商家充当的是顾客跟厂家之间的桥梁;又或者说,房屋中介也是一个代理,房屋中介替房主寻找租客,租客从中介那租到房子,房屋中介就是租客跟房主之间的桥梁。
开发过程中,A类要调用C类中的方法,但是却被禁止调用,这时就需要引进一个B类来充当代理,A类访问B类,B类访问C类,即A类通过B类去调用C类中的方法。
作用:
1、 功能增强:在原有的功能上增加新的功能。比如房屋中介在租房子的时候会收取相应的中介费,这个中介费就是房主所没有收取的,即在原先的功能之上,额外增加一些条件,或者说功能。
2、 控制访问:代理会控制你去访问目标类。比如商家不会让顾客直接去厂家那购买,或者厂家不提供顾客的个人购买。
实现方式:
1、静态代理
2、动态代理
二、静态代理
1、什么是静态代理?
代理类是手工创建的Java文件,同时代理的目标对象是固定的。(所谓静态就是在程序执行之前,其中的代理关系是确定好了的)
2、优缺点?
优点:代码清晰明了,符合思维逻辑,所以容易理解,使用起来比较方便
缺点:当目标类比较多的时候, 会产生大量的代理类。(为避免这个缺点,使用动态代理)
3、学习案例
首先创建一个接口类,如下:
public interface ToySell{
//在这个接口中定义一个方法
float sell(int amount);
}
创建一个厂家类(目标类),实现该接口(重写接口中的方法)
public class ToyFactory_A implements ToySell {
@Override
public float sell(int amount) {
//假设一个玩具的价格是25元
return 25.0f;
}
}
创建一个商家类(代理类),实现该接口(重写接口中的方法)
public class ToyShop_A implements ToySell{
//首先声明商家所代理的厂家具体是谁
private ToyFactory_A factory_a = new ToyFactory_A();
@Override
//实现销售玩具的功能
public float sell(int amount) {
//向厂家发送订单
float price = factory_a.sell(amount);
price = price+20;//商家需要代理费..增强功能,代理类在完成目标类方法调用后,增强了功能
//在目标类的方法调用之后,做其他的功能都是增强的意思
System.out.println("买一送一");
return price;
}
}
创建一个主函数,在主函数中声明商家,并通过商家去调用厂家中的方法,实现购买玩具。
public class shopMain {
public static void main(String[] args) {
//厂家代理的商家对象
ToyShop_A toyShop_a = new ToyShop_A();
float price = toyShop_a.sell(1);
System.out.println("通过A商家购买的玩具的单价是:"+price);
}
}
测试结果:
三、动态代理
1、什么是动态代理?
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并且动态地指定目标类,而不需要创建类文件。
2、动态代理的实现
jdk动态代理:使用Java反射包中的类和接口实现动态代理
cglib动态代理:属于第三方工具库,创建代理对象。其原理是继承,cglib通过继承目标类,创建子类,在子类中重写父类中的方法来实现功能的修改。(只要目标类能继承即可,即目标类不能是final的)
3、jdk动态代理
(1)关于反射机制(关于Method的使用)
创建一个接口service
public interface Helloservice{
public void sayHello(String name);
}
创建一个实现类,并实现该接口
public class HelloServiceIml implements HelloService{
@Override
public void sayHello(String name) {
System.out.println("你好,"+name);
}
}
创建一个测试类
public class TestApp{
public static void main(String[] args) {
//创建一个service对象
HelloService service = new HelloServiceImpl();
//直接通过对象来调用方法执行
service.sayHello("张三");
}
}
上面的测试类使用反射机制来执行
public class TestApp {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//使用 反射 机制执行sayHello方法。核心 Method(类中的方法)
HelloService target1 = new HelloServiceImpl();
//获取sayHello名称对应的method类对象
//.class获取类,.getMethod获取类中的方法
Method method = HelloService.class.getMethod("sayHello", String.class);//这个时候这个method就能代表sayHello方法了
//通过method可以执行sayHello方法调用
//表达的意思是:执行target1对象的sayHello,参数是张三
Object obj = method.invoke(target1,"张三");
/**
* invoke是Method类中的一个方法,表示执行方法的调用
* 参数:
* 1、Object,表示对象的,要执行这个对象的方法
* 2、Object...args,方法执行时的参数值
* 返回值:
* object:方法执行后的返回值
*/
}
}
测试结果:
(2) jdk动态代理的实现
在反射包中有三个类,InvocationHandler、Method、Proxy
★InvocationHandler接口
1)Invoke()方法:表示代理对象要执行的功能代码。
代理类要完成的功能:目标方法的执行,功能的增强。
代码原型
public Object invoke(Object proxy, Method method, Object[] args)
2)三个参数:
Object proxy:jdk创建的代理对象
Method method:目标类中的方法。
Object[] args:目标类中方法的参数
3)如何使用?
1、创建InvocationHandler接口的实现类
2、重写Invoke()方法,将所要实现的功能写在这里
★Method类(目标类中的方法)
作用:通过method执行某个目标类中的方法,如method.invoke();
method.invoke(目标对象,方法的参数)
比如:
//表达的意思是:执行target1对象的sayHello,参数是张三
Object obj = method.invoke(target1,“张三”);
★Proxy类(代替new的使用来创建代理对象)
1)方法:静态方法newProxyInstance()
方法原型:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
2)三个参数:
ClassLoader loader:类加载器,负责向内存中加载对象。通过使用反射机制来获取对应的ClassLoader类a,a.getClass().getClassLoader(),从而获取目标对象的类加载器
Class<?>[] interfaces:目标对象的接口,由反射获取。
InvocationHandler h:代理类要实现的功能,自己写的。
3)返回值:代理对象
(2) 动态代理的实现步骤
1)创建接口,定义目标类要完成的功能
2)创建目标类实现接口
3)创建InvocationHandler接口的实现类,在其invoke()方法中实现代理类的功能(调用目标方法+增强功能)
4) 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。
(3)学习案例
首先定义一个接口
public interface ToySell{
//在这个接口中定义一个方法
float sell(int amount);
}
创建接口的目标类
//目标类
public class ToyFactory_A implements ToySell{
@Override
public float sell(int amount) {
System.out.println("目标类方法");
return 50.0f;
}
}
创建接口的实现类,完成功能的实现与增强
public class MySellHandler implements InvocationHandler{
private Object service = null;
//动态代理:目标对象不是固定的,所以需要传入进来
//传入谁,就给谁创建代理
public MySellHandler(Object service) {
this.service = service;//给目标对象赋值
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//声明返回值
Object resp = null;
//执行目标方法
resp = method.invoke(service,args);
//功能增强
if(resp!=null){
float price = (float)resp;
price = price+10;
resp = price;
}
System.out.println("买一送一");
return resp;//返回价格
}
}
创建主函数
public class MainShop {
public static void main(String[] args) {
//使用proxy创建代理对象
//第一步,创建目标对象
ToySell toyFactory_a = new ToyFactory_A();
//第二步,创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(toyFactory_a);
//第三步,创建代理对象,注意将返回值转成接口
ToySell proxy = (ToySell) Proxy.newProxyInstance(toyFactory_a.getClass().getClassLoader(),
toyFactory_a.getClass().getInterfaces(),
handler);
//第四步,通过代理执行方法
float price = proxy.sell(1);
System.out.println("动态代理调用方法的结果是:"+price);
}
}
测试结果
总结
小白一枚,知识来源视频学习所汇集。可以去看视频更详细学习。学习视频链接