代理模式指的就是使用现一个代理类来代理另一个目标类的行为,比如说我们一般在租房子的时候,不直接和房东进行交涉,而通过房屋中介来进行操作,因为他们手里可能有很多的房源,对于房东来说,就可以直接与房屋中介进行交流。类似的例子数不胜数,又比如好莱坞的明星,都有他们自己的经济人,当然这里指的可不是宝强的经济人,开个玩笑,他们的经济人负责明星的经济活动,这里指的就是代理模式!
代理模式分为:静态代理模式,动态代模式(jdk动态代理),cglib动态代理模式三种!
一、 静态代理模式:
我们这里就用租房子的例子来说明原理,
- 类图如下 :
大概的说明一下:
有一个接口Host,里面有Rent租房的方法,然后让HostImpl房东来实现Host方法,这个就是目标类,真正要出租房子的房东,proxy为中介对象,它也实现Host方法,然后在类内部聚合了HostImpl对象,调用HostImpl,从而可以帮房东来出租房子,下面来看具体的代码实现:
- 代码
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
35public interface Host {
void Rent();
}
public class HostImpl implements Host {
public void Rent() {
System.out.println("房东要租房子");
}
}
public class proxy implements Host{
//聚合HostImpl
HostImpl host;
public proxy(HostImpl host) {
this.host = host;
}
public void Rent() {
System.out.println("代理开始工作");
//调用HostImpl中的Rent方法
host.Rent();
}
}
public class Client {
public static void main(String[] args) {
proxy proxy = new proxy(new HostImpl());
proxy.Rent();
}
} - 运行结果
静态代理:
优点:在不修改目标对象的功能前提下,能通过代理对象目标功能扩展
缺点:
(1)因为代理对象需要 与目标对象实现一样的接口,所有会有很多代理类
(2)一旦接口增加方法,目标对象与代理对象都要维护二、 动态代模式(jdk动态代理):
- 基本介绍:*
1)代理对象不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
2)代理对象的生成是利用JDK的API,动态的在内存中构建代理对象
3)动态代理也叫:JDK代理、接口代理 - 类图如下:
getProxyInstacne():
1.根据传入的对象(HostImpl),目标对象
2.利用反射机制,返回一个代理对象
3.然后通过代理对象,调用目标对象方法 - 代码实现
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55public interface Host {
void Rent();
}
public class HostImpl implements Host {
public void Rent() {
System.out.println("房东要租房子");
}
}
public class MyInvocationHadler implements InvocationHandler {
private Object target;
public MyInvocationHadler(Object target) {
this.target = target;
}
//执行目标方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理");
//利用反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
}
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象,生成一个代理对象
public Object getProxyInstance(){
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
*/
//1.ClassLoader loader:指定当前目标对象使用的类加载器
//2.Class<?>[] interfaces:目标对象实现的接口类型,使用泛型确认类型
//3.InvocationHandler h):事件处理,执行目标对象的方法,会触发事件处理器方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvocationHadler(target));
}
} - 测试结果
- 通过Debug可以观察到
- 类图所示
三、 Cglib动态代理模式:
基本介绍:
1)静态代理和JDK动态代理都要求目标对象是实现一个接口,但有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可以使目标对象子类来实现代理,这就是Cglib代理。
2)Cglib代理也叫子类代理,它是在内存中构建一个子类对象从而实现目标对象功能扩展,有时候也把Cglib代理归属到动态代理中。
3)Cglib代理是一个强大的高性能的代码生成包,这可以在运行期间扩展java类与实现java接口,它广泛的被许多AOP的框架使用,例如:Spring AOP中实现方法拦截
4)在AOP编程中如何选择代理模式:
4.1)目标对象需要实现接口,就用JDK代理
4.2)目标对象不需要实现接口,就用Cglib代理
5)Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类- Cglib使用的jar包:
cglib-2.2.jar
asm.jar
commons.jar
asm-tree.jar
- Cglib使用的jar包:
没有jar包的小伙伴可以下载食用:
链接:https://pan.baidu.com/s/16XEWkAGapxnmT4Li4ocKDA
提取码:sa4k
- 类图如下
- 代码实现
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
41
42
43
44
45
46
47public class HostImpl {
public void Rent(){
System.out.println("房东要租房子,cglib方式");
}
}
public class ProxyFactory implements MethodInterceptor {
//给一个目标对象
private Object target;
//构造器,用于初始化被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象,是target对象的代理对象
public Object getProxyInstance(){
//1.创建一个工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类对象,即代理对象
return enhancer.create();
}
//重写intercept方法,会调用目标对象的方法
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理模式*******开始");
Object returnVale = method.invoke(target, args);
System.out.println("cglib代理模式*******提交");
return returnVale;
}
}
public class Client {
public static void main(String[] args) {
//目标对象
HostImpl target = new HostImpl();
//获得到代理对象,并且将目标对象传递给代理对象
HostImpl proxyFactory = (HostImpl)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发intercept方法,从而实现对目标对象调用
proxyFactory.Rent();
}
} - 运行结果
- 通过Debug可以观察到
- 类图形式
总结:
cglib生成动态代理时,目标对象target和ProxyFactory 都不需要实现接口!