静态代理和动态代理设计模式

为什么需要静态代理和动态代理?

不知道,说不清楚,说不好....

静态代理设计模式:

①找到需要增强处理的类实现的接口

 

//玩家类实现的接口
public interface Player{
    boolean login();
}

 

//玩家类
public class PlayerImpl implements Player{
    public boolean login(){
        System.out.println("登录成功...");
  }; }

 

②创建一个代理(Proxy)类实现相同的接口

 

public class PlayerImplProxy implements Player

 

③在代理类中创建一个需要增强处理类的一个实例和需要增强处理的方法

 

//玩家代理类
public class PlayerImplProxy implements Player{
    private PlayerImpl play;
    public PlayerImplProxy(PlayerImpl play){
      this.play = play;
    }
    public void login(){
      System.out.println("欢迎登录...");
      System.out.println("登录成功...");
      System.out.println("请注意合理安排时间");
    };
}  

 

这样在实际应用过程中,可以通过调用代理类PlayerImplProxy的login()方法来达到增强处理的效果。

动态代理设计模式——加强后的静态代理设计模式

静态代理设计模式的使用范围具有局限性,而且有时候任务量比较庞大。其一,需要已知需要加强处理类的实现接口,其二,需要加强处理类实现的接口越多,任务量越大。

所以,一般情况下可以使用动态代理设计模式。

动态代理设计模式无需做太多的工作,因为java.lang.reflect.Proxy类都已经帮你做好了,我们只需要通过的Proxy类的newProxyInstance(params...)方法获取一个代理对象就好了。

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

 

ClassLoader loader:一般使用被代理的那个类的类加载器,targetClassInstance(被代理类的实例).getClass().getClassLoader(),通过类实例的getClass()方法获取该类的Class对象,再通过该类的Class对象的getClassLoader()方法获取该类的类的加载器。

 

Class<?>[] interfaces:该参数是被代理类所实现的所有接口,targetClassInstance.getClass().getInterfaces()获取被代理类所有实现的接口类型。

 

InvocationHandler h:InvocationHandler是一个接口,我们可以使用匿名内部类的方式来创建这个接口的对象,只需重写该接口的方法即可。

简单的动态代理设计模式代码如下:

 1 public class Test {
 2   public static void main(String[] args) {
 3         PlayerImpl play = new PlayerImpl();
 4         //获取ClassLoader参数
 5         ClassLoader loader = play.class.getClassLoader();
 6         //获取interfaces参数
 7         Class<?>[] interfaces = play.getClass().getInterfaces();
 8         //使用匿名内部类的形式创建InvocationHandler对象
 9         InvocationHandler h = new InvocationHandler() {
10             //重写该接口的方法
11             @Override
12             //三个参数:proxy:代理对象,不要使用
13             //        method:当前执行的方法
14             //        args:当前方法所需要的参数
15             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
16                 System.out.println("欢迎登录...");                
17                 Object returnValue = method.invoke(play, args);
18                 System.out.println("请注意合理安排时间");
19                 return returnValue;
20             }
21         };
22 
23         Object o = Proxy.newProxyInstance(loader, interfaces, h);
24 
25         if (o instanceof PlayerImpl) {
26             PlayerImpl playProxy = (ISuperStar) o;
27             playProxy.login();
28         }
29     }
30 }

在实际应用动态代理的过程中,我们可以使用两个接口来抽象出需要增强处理的前置方法和后置方法,通过创建一个ProxyFactory(代理工厂)类来获取需要代理对象。代码如下:

前置增强处理

public interface BeforeMethod {
    void before();
}

后置增强处理接口

public interface AfterMethod {
    void after();
}

代理对象工厂类:

 1 public class ProxyFactory {
 2     //前置处理对象
 3     private BeforeMethod before;
 4     //后置处理对象
 5     private AfterMethod after;
 6     //需要被加强处理的对象
 7     PlayerImpl player;
 8     //set和get方法
 9     public BeforeMethod getBeforeMethod() {
10         return before;
11     }
12 
13     public void setBeforeMethod(BeforeMethod before) {
14         this.before = before;
15     }
16 
17     public AfterMethod getAfterMethod() {
18         return after;
19     }
20 
21     public void setAfterMethod(AfterMethod after) {
22         this.after = after;
23     }
24 
25     public PlayerImpl getPlayer() {
26         return player;
27     }
28 
29     public void setPlayer(PlayerImpl player) {
30         this.player = player;
31     }
32     //创建代理对象的方法
33     public Object createProxyInstance() {
34         return Proxy.newProxyInstance(player.class.getClassLoader(), player.getClass().getInterfaces(), new InvocationHandler() {
35             @Override
36             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
37                 
38                 before.before();
39                 Object returnValue = method.invoke(player, args);
40                 after.after();
41 
42                 return returnValue;
43             }
44         });
45     }
46 }

测试类:

 1 public class Test {
 2     public static void main(String[] args) {
 3         ProxyFactory factory = new ProxyFactory();
 4         //设置工厂实例的属性
 5         factory.setBeforeMethod(new BeforeMethod() {
 6             @Override
 7             public void before() {
 8                 System.out.println("欢迎登录...");
 9             }
10         });
11         factory.setAfterMethod(new AfterMethod() {
12             @Override
13             public void after() {
14                 System.out.println("请注意合理安排时间");
15             }
16         });
17 
18         factory.setPlayer(new PlayerImpl());
19         Object proxy = factory.createProxyInstance();
20         if(proxy instanceof PlayerImpl){
21             PlayerImpl play = (PlayerImpl) proxy;
22             play.login();
23         }
24     }
25 }

上面是比较常用的写法。

其实静态代理和动态代理设计思路是一样,都是通过实现需要加强处理类(目标类)实现的接口,重写其需要加强处理的方法,来达到增强业务功能的目的。此外,前置处理和后置处理

可以只有其中一个,也可以同时拥有两个,根据具体的业务需求而定。动态代理和静态代理相比,更加简洁(毕竟Proxy类在内部做了很多事情),对目标类的要求也更低。但是,两者

都有一个特点就是,都要目标类实现一个或者多个接口。如果目标只是一个普通类,并未实现任何接口,这个时候我们可以使用Cglib子类代理来达到增强处理的结果,Cglib子类代理

不会,不做介绍。

简而言之,增强业务能力的方式已知的方式有两种:

①继承需要加强处理的类,在其子类中重写需要加强处理的方法。

②实现目标类(需要加强处理的类)所有实现的接口,创建一个代理对象,在代理类中组织一个增强处理的方法,达到增强业务能力的目的。

后续有时间会看一下:

①:Proxy类中为了实现动态代理做了哪些工作?

②:有没有其他增强业务功能的方法,什么情况选用哪种增强处理方式?各种增强处理方式的利与弊

 

posted on 2018-07-27 09:32  岁月磨平青春的棱角  阅读(160)  评论(0)    收藏  举报

导航