静态代理与动态代理
某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
有时候我们需要一些代理类来完成一些操作或访问控制,这个时候就需要产生相应的代理类,而产生代理类大致分为两种:
**》静态代理:由程序员编写或工具自动生成代理类源码,编译成字节码文件。即在程序运行前就已经存在字节码文件,并且代理类与委托类之间的关系就已经确定了。且这种关系相对是比较固定的,已经确定,后面扩展以及改动都需要修改源码。
》动态代理: 代理类的字节码文件,是动态生成的,当绑定委托对象后,可以生成字节码文件,并最终转化为代理类。这样被代理的对象可以动态指定。**
静态代理:
public class StaticProxy {
interface Animal{
public void voice();
}
class Dog implements Animal{
@Override
public void voice() {
// TODO Auto-generated method stub
System.out.println("dog: wang wang wang");
}
}
class ProxyDog implements Animal{
@Override
public void voice() {
// TODO Auto-generated method stub
Dog dog= new Dog();
System.out.println(" before voice......");
dog.voice();
System.out.println(" after voice......");
}
}
public static void main(String[] args) {
Animal dog= new StaticProxy().new ProxyDog();
dog.voice();
}
}
运行结果:
before voice......
dog: wang wang wang
after voice......
代理使用有点像AOP,这里是把被代理的类在代理类中创建(Dog dog= new Dog();),然后执行相关的操作。所以这里就是代理对象与被代理对象已经写死了,后面不容易扩展。
动态代理:
public class DynamicProxyTest {
interface IHello{
void sayHello();
void sayByeBye();
}
public static class Hello implements IHello{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hello World");
}
@Override
public void sayByeBye() {
// TODO Auto-generated method stub
System.out.println("Bye Bye!");
}
}
public static class DynamicProxy implements InvocationHandler{
Object originalObj;
Object bind(Object originalObj){
this.originalObj=originalObj;
return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(),originalObj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("welcome");
return method.invoke(originalObj, args);
}
}
public static void main(String[] args) {
IHello hello=(IHello) new DynamicProxy().bind(new Hello());
hello.sayHello();
hello.sayByeBye();
}
}
运行结果:
welcome
Hello World
welcome
Bye Bye!
动态代理不需要特定为被代理对象的每一个方法进行相应的配置操作,因此比较灵活,而对于静态代理操作起来就比较麻烦。
动态代理类继承InvocationHandler接口,绑定要代理的对象bind(),然后实现接口的invoke方法,这里面对方法进行相关代理操作。
这个里面关键一点是:Proxy.newProxyInstance(loader, interfaces, h)方法,传入参数被代理类的类加载器、被代理类的继承的所有接口、代理类方法调用处理器。返回的是一个实现了被代理对象的接口的实例对象(代理对象)。
**Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。**