是什么?作用?
- 定义:为另一个对象提供一个替身或占位符以控制对这个对象的访问 (控制访问)
- 分类
- 远程代理: 有点类似dubbo,调用代理的方法,会被代理利用网络转发到远程执行,并把结果通过网络返回给代理,最后返回给客户
- 虚拟代理: 作为创建开销大对象的代表,一般等该对象创建成功后,在委托给改对象
- 安全代理: 控制访问权限
- 智能代理: 提供对目标对象的额外服务
- 实现代理的方式
- 动态代理:利用反射在运行时创建代理类,并将方法的调用转发到你所指定的类
- 静态代理:代理类是运行之前就被创建出来了,相对于动态代理
- 动态代理实现方式分类
- JDK动态代理
- CGLIB动态代理
- 使用场景
AOP、防火墙、缓存、同步、。。。 - 类图
- Subject抽象主体角色: 可以是抽象类或者是接口
- RealSubject 具体的主体: 业务的真正执行者
- Proxy 代理类: 作为主题的代理类,通过访问代理类,来访问真正的主题类
代理示例
静态代理
代理背景: 假设我要去屈臣氏买点洗漱用品,我一哥们要出去买东西,所以就让他帮我买了
Subject
1
2
3
4
5
6
7/**
* 买洗漱用品接口
*/
public interface BuyCosmetics {
void shop();
}在屈臣氏可以买
1
2
3
4
5
6
7
8
9
10/**
* 屈臣氏
*/
public class Watsons implements BuyCosmetics{
public void shop() {
System.out.println("在屈臣氏买化妆品");
}
}让兄弟帮我买
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* 我朋友帮忙跑一趟
*/
public class MyFriend implements BuyCosmetics {
private Watsons watsons;
public MyFriend(Watsons watsons) {
this.watsons = watsons;
}
public void shop() {
watsons.shop();
}
}测试
1
2
3
4
5
6
7
8
9
10
11/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
Watsons watsons = new Watsons();
MyFriend myFriend = new MyFriend(watsons);
myFriend.shop();
}
}
这里实现了朋友帮我买东西的例子,和很多博客都不一样,所以如果有问题,清大家指出
JDK动态代理
使用java API实现动态代理,需要注意InvocationHandler接口, 它的作用是响应代理的任何调用,需要三步
- 创建代理调用处理器
- 实例化代理
- 通过代理调用行为
代码
Subject
同上在屈臣氏可以买
同上创建代理调用处理器
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/**
* 动态代理
* 作用:
* 1. 生成代理对象
* 2. 指定需要代理的真实对象
* 3. 调用真实对象的操作
*/
public class DynamicProxy implements InvocationHandler {
/**
* 要代理的真实对象
*/
private BuyCosmetics proxyObject;
/**
* 这个方法用来创建代理类,并实例化代理类
*/
public BuyCosmetics getProxy(BuyCosmetics proxyObject) {
this.proxyObject = proxyObject;
return (BuyCosmetics) Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
proxyObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 利用反射调用真实对象的方法, 可以在调用前后添加你的业务
Object result = method.invoke(proxyObject, args);
return result;
}
}测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Main {
public static void main(String[] args) {
// 1. 创建调用处理器对象
DynamicProxy dynamicProxy = new DynamicProxy();
// 2. 创建真实对象
Watsons watsons = new Watsons();
// 3. 创建动态代理类 传入目标对象
BuyCosmetics buyCosmetics = dynamicProxy.getProxy(watsons);
// 4. 执行行为
buyCosmetics.shop();
}
}
CGLIB动态代理
Subject
同上在屈臣氏可以买
同上创建代理调用处理器
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
37
38
39
40
41import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 代理调用处理器
*/
public class DynamicProxy implements MethodInterceptor {
private Enhancer enhancer;
public Object getProxy(Class clazz) {
enhancer = new Enhancer();
// 设置需要代理的类
enhancer.setSuperclass(clazz);
//设置需要代理的类
enhancer.setCallback(this);
// 用于创建无参的目标对象代理类,对于有参构造器则调用Enhancer.create(Class[] argumentTypes, Object[] arguments),第一个参数表示参数类型,第二个参数表示参数的值
return enhancer.create();
}
/**
*
* @param o Subject类, 即被代理的类
* @param method Method表示拦截的方法
* @param objects 被代理类的参数
* @param methodProxy MethodProxy表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用前");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("调用后");
return result;
}
}测试
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* cglib动态代理 test
*/
public class MainClient {
public static void main(String[] args) {
DynamicProxy dynamicProxy = new DynamicProxy();
BuyCosmetics watsons = (Watsons)dynamicProxy.getProxy(Watsons.class);
watsons.shop();
System.out.println(watsons.getClass().getName());
}
}结果
调用前
在屈臣氏买化妆品
调用后
com.example.demo.代理模式.CGLIB动态代理.Watsons$$EnhancerByCGLIB$$2f4d9538
总结
- 代理模式使用最多的就是,智能代理, 会为被代理对象提供额外的服务
- 类图和装饰器模式很像,主要看使用的目的,还有装饰器一般持有的是基类,而代理一般持有的具体的类
- 优点:
- 良好的扩展性。修改被代理角色并不影响调用者使用代理,对于调用者,被代理角色是透明的。
- 隔离,降低耦合度。代理角色协调调用者和被代理角色,被代理角色只需实现本身关心的业务,非自己本职的业务通过代理处理和隔离。 - 缺点:
- 访问时间可能延长
- 类数量增加