书成

再这样堕落下去就给我去死啊你这混蛋!!!

0%

Jdk 动态代理

代理模式

 所谓代理模式,就是为其它对象提供一个代理来控制对目标对象的访问,代理类不实现具体的服务,利用委托类来完成服务。

静态代理

 静态代理十分简单。创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法 。

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
// 设计一个接口
public interface Hello {
public void say(String s) throws IllegalArgumentException;
}

// 被代理类实现该接口
public class HelloImpl implements Hello {
@Override
public void say(String s) throws IllegalArgumentException{
if(s == null || s.length() == 0)
throw new IllegalArgumentException("参数不合法");
System.out.println(s);
}
}

// 代理类也实现该接口
public class HelloStaticProxy implements Hello {
Hello hello; // 被代理的对象

public HelloStaticProxy(Hello hello){
this.hello = hello;
}
@Override
public void say(String s) throws IllegalArgumentException {
System.out.println("before method invoke");
String re = null;
boolean isException = false;
try{
this.hello.say(s);
}catch (IllegalArgumentException e){
isException = true;
}
System.out.println("after method invoke");
if(isException)
System.out.println("after method throw Exception");
}
public static void main(String[] args){
Hello hello = new HelloImpl();
Hello proxy = new HelloStaticProxy(hello); // 将被代理对象传入新建一个代理对象
proxy.say(null); // 代理类在执行具体方法时通过所持用的被代理类完成调用
System.out.println("------------------");
proxy.say("hello");
}
}

 以上代码运行结果如下:

1
2
3
4
5
6
7
before method invoke
after method invoke
after method throw Exception
------------------
before method invoke
hello
after method invoke

 这样,当需要代理一个类的时候,只要编写一个该类的静态代理对象即可,但是,如果需要代理的对象很多,就需要编写大量的代理类,十分麻烦 。

动态代理

 动态代理能够利用反射机制在程序运行期间生成代理类。在 java.lang.reflect 包下的 Proxy 类有一个静态方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),通过该方法可以获得动态代理类。它需要一个类加载器,类的接口数组,以及一个实现 InvocationHandler 接口的类。

  InvocationHandler 中只声明了一个方法:Object invoke(Object proxy, Method method, Object[] args) throws Throwable ,通过这个方法,可以调用被代理类的方法,需要注意,invoke 参数中的 proxy 表示的是代理对象,而不是被代理对象,因此 method.invoke() 传入的参数不能是它,否则会循环调用。

 上面的接口与接口实现类不变,创建一个实现了 InvocationHandler 的类完成动态代理:

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
public class MyProxyHandler implements InvocationHandler {
Object target; // 被代理对象
public MyProxyHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method invoke");
Object re = null;
boolean isException = false;
try{
re = method.invoke(target, args); // 调用被代理对象的方法
}catch (Exception e){
isException = true;
}
System.out.println("after method invoke");
if(isException) {
System.out.println("after method throw Exception");
return null;
}
return re;
}

public static void main(String[] args){
Hello hello = new HelloImpl();
Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(), new MyProxyHandler(hello));
helloProxy.say(null);
System.out.println("-----------------");
helloProxy.say("hello");
}
}

 结果如下:

1
2
3
4
5
6
7
before method invoke
after method invoke
after method throw Exception
-----------------
before method invoke
hello
after method invoke

 jdk动态代理必须要依靠接口实现,因为生成的代理类是 Proxy 的子类,而 Java 不允许多继承,所以需要接口来连接代理类与被代理类。