0%

Java动态代理

Java动态代理

最近在看java的动态代理,做下笔记

什么是代理

代购:如果你想买的东西在国外,你一般不会飞过去买完再飞回来,而是有个中介,帮你处理这件事,这个中介就是代购,也就是代理。帮你办一件事就是代理。

客户 —– 代理(代购) ——国外商场

为什么找代购?

便宜省心专业,我不能自己去国外买。同时代购为了自己的优势,不让买家接触自己的进货渠道,你想要这个价格和服务就只能通过代购。所以很多时候只能通过代购来买东西。

类比到java

A类想调用C类的方法,但是C不允许A直接调用,这时候可以通过代理B来进行操作。

A->B->C

C->B->A

看起来很傻对不对?但是是实际情况需求。

比如付款需要短信验证码,你不可能直接找移动联通说发条短信。而是找第三方公司,他们总包了一个大业务,一天几十万条给移动联通签合同。然后你买他们的,他们再付钱给移动联通。

代理模式

什么是代理模式

A类想调用C类的方法,但是C不允许A直接调用,这时候可以通过代理B来进行操作。这种程序的调用关系称为代理模式。

代理模式的作用

1、功能增强 :在原有功能上增加新功能

2、控制访问 : 控制你直接访问目标

如何实现代理

静态代理

1、代理类手动实现

2、代理的目标类是确定的

实现一个静态代理

1、创建一个接口,定义卖U盘的方法

2、创建厂家类,实现1步骤接口

3、创建商家,就是代理实现1步骤接口

4、定义客户类

定义UsbSell接口

1
2
3
4
5
6
7
8
9

//厂家和商家都要完成的功能
public interface UsbSell{
//购买的数量,返回u盘价格
float sell(int amount);

}


金士顿厂家

1
2
3
4
5
6
7
8
9
10
11
12
13
public class UsbKingFactory implements UsbSell{
@Override
public float sell(int amount){
//一个U盘85 10000起卖
if (amount < 10000){
return flase
}
else{
return 85.0f;
}

}
}

淘宝商家

1
2
3
4
5
6
7
8
9
10
public class TaoBao implements UsbSell{
private UsbKingFactory factory = new UsbKingFactory();
@Override
public float sell(int amount){
//一个我就卖赚25,增强功能,而且我还可以增强各种功能,比如我换包装,我捆绑销售。我好评返现啥的。
float price = factory.sell(amount);
price = price + 25;
return price;
}
}

客户

1
2
3
4
5
6
7
public class ShopMain{
TaoBao taobao = new TaoBao();
float price = taobao.sell(1);
System.out.println(price);
//可以说是被商家剥削了
}

代理类一般都 会调用目标类的方法,然后额外做其他功能。

缺点

1、如果厂家不止一家,就要创建各种厂家类,然后代理商也要调用各种厂家类的方法。所以代理商类也成倍增长。

2、如果接口增减功能,所有实现此接口的所有类都会被影响。

动态代理

在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态指定代理的目标类。

作用

1、控制访问
2、功能增强

实现方式

1、JDK动态代理
反射包 java.lang.reflect 里面有三个类:InvocationHandler,Method,Proxy

其中 InvocationHandler接口有一个: invoke() 方法,我们需要实现这个接口并在invoke方法中完成下面的功能
1、调用目标方法
2、功能增强
为什么?因为这个 invoke() 会在动态代理对象调用任意方法的时候出发,是动态代理的核心。

怎么用?

1、创建类实现这个接口InvocationHandler?

2、重写invoke方法,把要完成的功能写在里面。

3、生成动态代理对象(生成动态代理对象的过程就是把动态的代码具体到某个类的动态代理对象)

4、执行对应方法。

例子

1、必须有接口,(比如一个Subject有一个doSomething方法)

2、必须有实现这个接口的类 (比如RealSubject实现这个接口,并且是一个类)

3、设计动态代理类ProxyHandler继承InvocationHandler,在invoke中 通过反射实时调用我们想调用的方法,并做功能增强,最终返回返回值。

4、应用动态代理:声明动态代理的类,生成动态代理对象(new RealSubject,并通过Proxy.newProxyInstance生成动态代理对象。)

特点:

1、无侵入式的代码扩展。

2、无需实现大量的类,可通过反射特性动态执行方法。

1
2
3
4
5
6
7
8
package test;

//声明一个接口
public interface Subject
{
public void doSomething();
}

1
2
3
4
5
6
7
8
9
10
package test;

//实现接口
public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}

上面两块代码不是确定的,可以实现成千上万的接口和对应类,然后通过动态代理来动态调用和功能增强上面的类的对象。

下面就是动态代理类必须实现InvocationHandler接口,并在invoke中写下面的逻辑代码:1、调用目标对象方法 2、功能增强

(其中bind不是必须的,也可以在别的地方进行动态代理的生成,当然封装成bind函数在生成动态代理的时候更方便。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package test;

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

public class ProxyHandler implements InvocationHandler
{
//要执行的目标对象,就是动态代理的目标,动态代理顾名思义这个目标是动态的,是传入的。
private Object tar;

//绑定委托对象,并返回代理类,相当于生成了一个代理对象。后续就是用这个代理对象进行方法调用的
public Object bind(Object tar)
{
// 指定动态对象的对应目标,传入参数后,动态代理的对象目标就确定了,不再是模糊的。
this.tar = tar;
// 绑定该类实现的所有接口,取得动态代理对象,并返回,bind函数本身就是创建动态代理。
return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
tar.getClass().getInterfaces(),
this);
}
//invoke里面主要写两种:1、调用目标对象方法 2、功能增强
public Object invoke(Object proxy , Method method , Object[] args)throws Throwable
{
Object result = null;
//这里就可以进行所谓的AOP编程了

//1、根据反射调用对应对象的对应方法,这里就是动态代理能实现的关键。利用的是反射特性,可以动态调用各种对象的各种参数的各种方法
result = method.invoke(tar,args);

//2、功能增强
//result = chuli(result)
//在调用具体函数方法后,返回对应结果
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
public class TestProxy
{
public static void main(String args[])
{
ProxyHandler proxy = new ProxyHandler();
//绑定该类实现的所有接口,生成动态代理对象
Subject sub = (Subject) proxy.bind(new RealSubject());
//虽然下面调用的是doSomthing,但是实际上是调用的Invoke,同时传入了参数(这里参数为空)
sub.doSomething();
}

看完代码,现在我来回答,动态代理的作用是什么:

  1. Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大;
  2. 可以实现AOP编程,实际上静态代理也可以实现,总的来说,AOP可以算作是代理模式的一个典型应用;
  3. 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。

采用署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0)许可协议
「分享也是一种学习」