静态代理和动态代理

一、代理模式

定义:代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。这种类型的设计模式属于结构型模式。

代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:

抽象主题角色:可以是接口,也可以是抽象类;
委托类角色:真实主题角色,业务逻辑的具体执行者;
代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

二、静态代理

所谓静态代理是指,在程序运行前,由程序员创建或特定工具自动生成源代码并对其编译生成.class文件。静态代理的实现只需要三步:首先,定义业务接口;其次,实现业务接口;然后,定义代理类并实现业务接口;最后便可通过客户端进行调用。例如,

1.创建接口

1 package DesignPattern.staticproxy;
2 
3 public interface ITeacherDao {
4     void teach();
5 }
View Code

2.目标类实现接口

package DesignPattern.staticproxy;

public class TeacherDao implements ITeacherDao{
    @Override
    public void teach() {
        System.out.println("老师正在授课……");
    }
}
View Code

3.代理类实现接口,对目标类添加扩展功能

 1 package DesignPattern.staticproxy;
 2 
 3 public class TeacherDaoProxy implements ITeacherDao {
 4     private ITeacherDao target;
 5 
 6     public TeacherDaoProxy(ITeacherDao target) {
 7         this.target = target;
 8     }
 9     @Override
10     public void teach() {
11         System.out.println("开始代理,完成某些操作……");
12         target.teach();
13         System.out.println("提交……");
14     }
15 }
View Code

4.客户端调用

 1 package DesignPattern.staticproxy;
 2 
 3 public class client {
 4     public static void main(String[] args) {
 5 //        创建目标对象(被代理对象)
 6         ITeacherDao teacherDao = new TeacherDao();
 7 //        TeacherDao teacherDao = new TeacherDao();
 8 //        创建代理对象,同时将被代理对象传递给代理对象
 9         TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
10 //         通过代理对象调用被代理对象的方法
11         teacherDaoProxy.teach();
12     }
13 }
View Code

静态代理优缺点

优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

开闭原则:开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简单来说:就是为了使程序的扩展性好,易于维护和升级。

缺点:

1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。

三、jdk动态代理

如何解决静态代理的缺点呢? 这里就得说说动态代理了。

在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。(利用反射机制在运行时创建代理类。)

1.创建接口

1 package DesignPattern.Dynamicproxy;
2 
3 public interface ITeacherDao {
4     void teach();
5     void sayHello(String name);
6 }
View Code

2.目标类实现接口

 1 package DesignPattern.Dynamicproxy;
 2 
 3 public class TeacherDao implements ITeacherDao{
 4     @Override
 5     public void teach() {
 6         System.out.println("老师授课中……");
 7     }
 8 
 9 
10     @Override
11     public void sayHello(String name) {
12         System.out.println("hello!"+name);
13     }
14 }
View Code

3.动态代理

 1 package DesignPattern.Dynamicproxy;
 2 import java.lang.reflect.InvocationHandler;
 3 import java.lang.reflect.Method;
 4 import java.lang.reflect.Proxy;
 5 public class ProxyFactory {
 6     //维护一个目标对象,Object
 7     private Object target;
 8 //构造器,对target进行初始化
 9     public ProxyFactory(Object target) {
10         this.target = target;
11     }
12 //给目标对象生成一个代理对象
13     public Object getProxyInstance(){
14         //说明
15         /*
16          *  public static Object newProxyInstance(ClassLoader loader,
17                                           Class<?>[] interfaces,
18                                           InvocationHandler h)
19 
20             //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
21             //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
22             //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
23          */
24         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
25                 target.getClass().getInterfaces(),
26                 new InvocationHandler() {
27                     @Override
28                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
29                         System.out.println("JDK代理开始……");
30                         //反射机制调用目标对象的方法
31                         Object returnVal = method.invoke(target,args);
32                         System.out.println("JDK代理提交……");
33                         return returnVal;
34                     }
35                 });
36     }
37 }
View Code

4..客户端调用

 1 package DesignPattern.Dynamicproxy;
 2 
 3 public class client {
 4     public static void main(String[] args) {
 5         //创建目标对象
 6         ITeacherDao target = new TeacherDao();
 7         //给目标对象,创建代理对象,可以转成ITeacherDao
 8         ITeacherDao proxyInstance =(ITeacherDao)new ProxyFactory(target).getProxyInstance();
 9         // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
10         System.out.println("proxyInstance:"+proxyInstance.getClass());
11         //通过代理对象调用目标对象的方法
12         proxyInstance.teach();
13         proxyInstance.sayHello("Tom");
14     }
15 }
View Code

优缺点:

优点:

相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。

缺点:

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用JDK动态代理。

原文地址:https://www.cnblogs.com/jingpeng77/p/12973211.html