JAVA中基于JDK的静态代理和动态代理
1. 什么是代理
代理在我们生活中也就是所谓的中介。那么为什么我们需要中介呢?
举个例子来说:
我现在想买二手房,但是要面临很多问题。比如找房源,房子质量测评,房子过户合同要如何编写等一系列繁琐的事情。这个时候就需要中介出场了,他们可以帮我们把其他需要事前和事后处理的事情都帮我们做了。
2. 代理的功能
1.只要关注接口本身的功能而不用过多关注具体如何实现。具体的实现由代理类来进行操作。
2.遵循开闭原则,在不修改需求的情况下可以增加很多的功能。
3. 如何实现
代理的实现方式有很多,在JAVA中具体的代理类型有两种,分别是静态代理和动态代理。它的实现方式也有两种,分别是基于JDK和基于cglib的方式,想要知道它们的具体区别请直接跳到第4章节,本篇我们就来讲讲基于JDK的方式实现。下面我们来聊聊他们是如何实现的。
3.1 静态代理
顾名思义这个是我们在代码运行前就实现了。直接通过程序员硬编码书写出来的。
代理接口
//我的想法是要买房子
public interface MyIdea {
void buyHouse();
}
委托类,处理具体业务
public class MyIdeaimpl implements MyIdea{
@Override
public void buyHouse() {
System.out.println("我想买房子");
}
}
代理的实现类
public class MyIdeaProxy implements MyIdea{
MyIdeaimpl myIdeaimpl;
public MyIdeaProxy(MyIdeaimpl myIdeaimpl){
this.myIdeaimpl=myIdeaimpl;
}
@Override
public void buyHouse() {
searchHouse();
myIdeaimpl.buyHouse();
dealDoc();
}
/**
* 处理合同
*/
public void dealDoc(){
System.out.println("处理合同...");
}
/**
* 找合适的房源
*/
public void searchHouse(){
System.out.println("寻找合适的房子...");
}
}
代理工厂类
public class MyIdeaFactory {
public static MyIdea getInstance() {
return new MyIdeaProxy(new MyIdeaimpl());
}
}
主函数入口
public static void main(String[] args) {
//自己买房子
MyIdeaimpl myIdeaimpl=new MyIdeaimpl();
myIdeaimpl.buyHouse();
System.out.println("===================================");
//通过代理工厂买房子,此时客户并不知道代理工厂给出的是代理类还是委托类
MyIdea myidea = MyIdeaFactory.getInstance();
myidea.buyHouse();
}
运行结果:
我想买房子
===================================
寻找合适的房子...
我想买房子
处理合同...
总结
优点:我们可以看到,在经过代理的加持下,我们可以在不修改原有的需求下增加很多的功能,在后期的有修改需求的时候只需要替换代理类即可。
缺点:接口里的方法都要在委托类和代理类中实现,当接口中的方法较多时就难以胜任了。
3.2 动态代理
在动态代理中,委托类和代理类是在运行时生成的。也就是说并不存在字节码文件。并且一个处理器可以动态代理出多个不同类型的委托类和接口。
实现了InvocationHandler的处理器
public class DynamicInvocationHandler implements InvocationHandler {
private Object object;
public DynamicInvocationHandler(Object o){
this.object=o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始....");
method.invoke(object,args);
System.out.println("结束...");
return null;
}
}
我们再来创建一个接口和委托类
public interface MyIdea2 {
void buyCar();
}
public class MyIdea2impl implements MyIdea2{
@Override
public void buyCar() {
System.out.println("我想买车车...");
}
}
主函数
//我们可以看到MyIdea和MyIdea2是不同的接口,里面的方法也不一样。但是可以复用同一个代理类
public static void main(String[] args) {
MyIdeaimpl myIdeaimpl=new MyIdeaimpl();
MyIdea2impl myIdea2iml=new MyIdea2impl();
DynamicInvocationHandler dynamicInvocationHandler=new DynamicInvocationHandler(myIdeaimpl);
DynamicInvocationHandler dynamicInvocationHandler2=new DynamicInvocationHandler(myIdea2iml);
MyIdea dynaMyIdea = (MyIdea) Proxy.newProxyInstance(MyIdeaimpl.class.getClassLoader(), MyIdeaimpl.class.getInterfaces(), dynamicInvocationHandler);
dynaMyIdea.buyHouse();
MyIdea2 dynaMyIdea2 = (MyIdea2) Proxy.newProxyInstance(MyIdea2impl.class.getClassLoader(), MyIdea2impl.class.getInterfaces(), dynamicInvocationHandler2);
dynaMyIdea2.buyCar();
}
运行结果:
开始....
我想买房子
结束...
开始....
我想买车车...
结束...
总结:
1、通过这个动态代理类生成的代理对象不依赖具体的委托类和接口,可以复用这个动态代理类。实现了AOP功能,可以给程序提供日常的日志记录,访问统计,统一异常处理等操作。
2、再来说说缺点,动态代理也有它的缺点和局限性,一个是性能方面,动态代理的性能比较差。第二个他是面向接口的编程,就是它始终无法摆脱interface的枷锁。
4. cglib和jdk代理的区别
cglib | jdk | |
---|---|---|
生成代理类速度 | 慢 | 快 |
代理类执行速度 | 快 | 慢 |
能否对普通类进行代理 | 能 | 不能 |
能否对接口进行代理 | 能 | 能 |
能否对final类进行代理 | 不能 | 能 |
能否对final方法进行代理 | 不能 | 能 |