您的位置:首页 > 编程语言 > Java开发

Spring的静态代理和动态代理

2017-02-15 00:00 381 查看
代理模式主要有两种:静态代理和动态代理

1,静态代理:

比如要在输出“HelloWorld”前打印一个字符串“Welcome”

A:先定义一个接口类

public interface HelloWorldIF {
public void print();
// public void say();
}

B:定义一个该接口的实现类

public class HelloWorldImpl implements HelloWorldIF{

public void print(){
System.out.println("HelloWorld");
}
// public void say(){
// System.out.println("Say Hello!");
// }
}

C:定义一个静态代理类

public class StaticProxy implements HelloWorldIF{

public HelloWorld helloWorld ;
public StaticProxy(HelloWorld helloWorld){
this.helloWorld = helloWorld;
}

public void print(){
System.out.println("Welcome");
//相当于回调
helloWorld.print();
}

// public void say(){
// //相当于回调
// helloWorld.say();
// }
}

可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法(把上面所有的代码的注释给去掉),所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。

2,动态代理

动态代理与普通代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每个方法进行中转。

动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该方法就是调用被代理接口的所有方法时需要调用的,而invoke方法返回的值是被代理接口的一个实现类。

代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
public class DynamicProxy implements InvocationHandler{

private Object object;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
//Proxy.newProxyInstance的第三个参数是表明这些被拦截的方法执行时需要执行哪个InvocationHandler的invoke方法
public Object bindRelation(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
//拦截关联的这个实现类的方法被调用时将被执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Welcome");
Object result = method.invoke(object, args);
return result;
}

}

测试类:

public class TestDynamicProxy {
public static void main(String[] args){
HelloWorld helloWorld = new HelloWorldImpl();
DynamicProxy dp = new DynamicProxy();
//在这里绑定的是HelloWorld,也就是HelloWorld是被代理接口。所以绑定关系时,需要传递一个HelloWorld的实现类的实例化对象。
HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);
helloWorld1.print();
helloWorld1.say();

//helloWorld2将不被拦截
HelloWorld helloWorld2 = new HelloWorldImpl();
helloWorld2.print();
helloWorld2.say();

}
}

在测试类里调用实现类的print和say方法,因为代理类里代理了HelloWorld的所有方法。所以就不需要像静态代理类那样一一实现了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: