代理模式就是不直接对外提供其实现类,而是提供其代理类,隐藏实现类的细节,通常还用于在真实的实现的前后添加一部分逻辑
静态代理
目标接口1
2
3public interface Subject {
void hello();
}
委托类1
2
3
4
5
6
7public class RealSubject implements Subject {
@Override
public void hello() {
System.out.println("hello");
}
}
代理类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//代理类为了和其实现类功能一样,所以也要实现目标接口类
public class StaticProxy implements Subject {
//代理对象持有委托类的引用
private Subject realSubject;
public StaticProxy(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void hello() {
System.out.println("静态代理before");
realSubject.hello();
System.out.println("静态代理after");
}
public static void main(String[] args) {
Subject subject = new StaticProxy(new RealSubject());
//调用代理类对象方法
subject.hello();
}
}
上面这种方式成为静态代理,静态代理的局限在于运行前必须编写好代理类,如果需要被代理多个方法就会有很多冗余代码
动态代理
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数
- jdk自带的动态代理
在使用动态代理时,需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口
由动态代理类委托中间类,中间类持有真正目标类的引用,其实是两层静态代理
1 | public class JDKDynamicProxy implements InvocationHandler { |
1 | com.sun.proxy.$Proxy0 |
特点:
- 类名:格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,这样可以节省不必要的代码重复生成,提高了代理类的创建效率
- 类继承关系:Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且该类还实现了其所代理的一组接口
缺点:
Proxy只能对interface进行代理,无法实现对class的动态代理。观察动态生成的代理继承关系图可知原因,他们已经有一个固定的父类叫做Proxy,Java语法限定其不能再继承其他的父类
- cglib实现的动态代理
CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充
- 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
- 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
- 缺点:对于final方法,无法进行代理
1 | public class CglibDynamicProxy { |
1 | me.changjie.proxy.RealSubject$$EnhancerByCGLIB$$636b402a |
配合过滤器使用可选择性的对方法进行拦截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
42public class CglibDynamicProxy2 {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
Callback interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getName());
System.out.println("cglib动态代理2before");
//调用父类方法
methodProxy.invokeSuper(o, objects);
System.out.println("cglib动态代理2after");
return null;
}
};
//NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截
enhancer.setCallbacks(new Callback[]{interceptor, NoOp.INSTANCE});
CallbackFilter filter = new CallbackFilter() {
@Override
public int accept(Method method) {
if (method.getName().equals("hello2")) {
System.out.println("我将此方法过滤掉了,不对该方法进行拦截");
return 1;//对应拦截器数组索引,NoOp.INSTANCE
}
return 0;//对应拦截器数组索引,interceptor
}
};
enhancer.setCallbackFilter(filter);
RealSubject realSubject = (RealSubject) enhancer.create();
realSubject.hello();
realSubject.hello2();
}
}
1 | 我将此方法过滤掉了,不对该方法进行拦截 |