Java设计模式之代理模式

代理模式

在代理模式(Proxy Pattern)中:

①一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

②我们创建具有现有对象的对象,以便向外界提供功能接口。

介绍

作用:为其他对象提供一种代理以控制对这个对象的访问,举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接联系明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

优点: 1、职责清晰  2、高扩展性  3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。


 

一、静态代理

我们将创建一个SomeService接口和实现SomeService接口的实体类。ServiceProxy是一个代理类,减少ServiceSomeImpl对象加载的内存占用。proxyTest,我们的测试类使用ServiceProxy来获取加载的SomeService对象,并按需求进行打印输入。

实现步骤1

创建一个接口。

1 // 目标接口
2 public interface SomeService {
3     String doSome();
4 }

步骤2

创建实现接口的实体类。

1 // 目标类
2 public class SomeServiceImpl implements SomeService{
3     @Override
4     public String doSome() {
5         return "I come from China";
6 } 7 }

步骤3

创建实现接口的代理类。

 1 // 静态代理类,要实现和目标类一样的接口
 2 public class ServiceProxy implements SomeService{
 3     SomeService target;
 4     
 5     @Override
 6     public String doSome() {
 7         // 调用目标接口的方法,使方法输出的内容变为全部变为大写。
 8         return target.doSome().toUpperCase();
 9     }
10     
11     // 构造函数
12     public ServiceProxy() {
13     }
14     
15     public ServiceProxy(SomeService target) {
16         super();
17         this.target = target;
18     }
19 }

步骤4

创建测试类。

 1 // 测试类
 2 public class TestProxy {
 3     public static void main(String[] args) {
 4         // 定义目标对象
 5         SomeService target = new SomeServiceImpl();
 6         // 定义目标对象的代理对象(通过代理对象对目标对象进行增强——输入内容变为大写)
 7         SomeService proxy = new ServiceProxy(target);
 8         // 代理对象调用目标接口中的方法
 9         String result = proxy.doSome();
10         System.out.println("输出结果:" + result);
11     }
12 }

步骤5

执行测试类的main方法,执行结果如下:

输出结果:I COME FROM CHINA

 

二、动态代理(不需要手动创建代理类。1.如果目标对象实现了接口,采用JDK动态代理,2.如果目标对象没有实现接口,必须采用CGLIB动态代理)


 

①JDK动态代理

1.java.lang.reflect.Proxy:生成动态代理类和对象; 

2.java.lang.reflect.InvocationHandler(处理器接口):可以通过invoke方法实现对真实角色的代理访问。每次通过 Proxy 生成的代理类对象都要指定对应的处理器对象。3

3.我们将创建一个SomeService接口和实现SomeService接口的实体类,以及一个测试类。

实现步骤1

创建一个接口。

1 // 目标接口
2 public interface SomeService {
3     String doSome();
4 }

步骤2

创建实现接口的实体类。

1 // 目标类
2 public class SomeServiceImpl implements SomeService{
3     @Override
4     public String doSome() {
5         return "I come from China";     }
6 }

步骤3

创建测试类。

 1 // 测试类
 2 public class TestProxy {
 3     public static void main(String[] args) {
 4         // 定义目标对象
 5         final SomeService target = new SomeServiceImpl();
 6         // 定义目标对象的代理对象
 7         // 参数1——目标类的类加载器:target.getClass().getClassLoader()
 8         // 参数2——目标类实现的所有接口:target.getClass().getInterfaces()
 9         // 参数3——调用处理器:new InvocationHandler()
10         SomeService proxy = (SomeService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
11                 new InvocationHandler() {
12                     // 参数1——proxy:代理对象
13                     // 参数2——method:目标方法
14                     // 参数3——args:目标方法的参数
15                     @Override
16                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
17                         // 调用目标方法
18                         String result1 = (String) method.invoke(target, args);
19                         return result1.toUpperCase();
20                     }
21                 });
22         // 代理对象调用目标接口中的方法
23         String result2 = proxy.doSome();
24         System.out.println("输出结果:" + result2);
25     }
26 }

步骤4

执行测试类的main方法,执行结果如下:

输出结果:I COME FROM CHINA

 


 

CGLIB动态代理

1.CGLIB动态代理是针对代理的类, 动态生成一个子类, 然后子类覆盖代理类中的方法, 如果是private或是final类修饰的方法,则不会被重写。

2.CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

3.作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib

实现步骤1

在进行代码编写之前,必须导入cglib-nodep的jar包,本案例导入的jar包为 cglib-nodep-3.2.10.jar,在这给大家提供一个该jar包的下载地址:https://mvnrepository.com/artifact/cglib/cglib-nodep/3.2.10

步骤2

创建目标实体类。

1 // 目标类
2 public class SomeServiceImpl {
3     
4     public String doSome() {
5         return "I come from China";
6     }
7 }

步骤3

创建cglib动态代理工厂。

 1 // cglib动态代理工厂
 2 public class CglibProxyFactory implements MethodInterceptor{
 3     
 4     // 创建目标对象
 5     private SomeServiceImpl target;
 6     // 创建构造器
 7     public CglibProxyFactory() {
 8         super();
 9     }
10     public CglibProxyFactory(SomeServiceImpl target) {
11         super();
12         this.target = target;
13     }
14     
15     // 创建cglib代理对象的方法
16     public SomeServiceImpl proxyCreator() {
17         // 创建增强器
18         Enhancer enhancer = new Enhancer();
19         // 指定父类(指定目标类)
20         enhancer.setSuperclass(SomeServiceImpl.class);
21         // 指定回调接口对象
22         enhancer.setCallback(this);
23         // 创建cglib代理对象并返回该对象
24         return (SomeServiceImpl) enhancer.create();
25     }
26     
27     @Override
28     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
29         // 反射调用目标对象方法,实现增强操作
30         String result1 = (String) method.invoke(target, args);
31         return result1.toUpperCase();
32     }
33 }

步骤4

创建测试类。

 1 // 测试类
 2 public class TestProxy {
 3     public static void main(String[] args) {
 4         // 定义目标对象
 5         SomeServiceImpl target = new SomeServiceImpl();
 6         // 定义目标对象的代理对象(通过cglib代理对象的方法进行创建)
 7         SomeServiceImpl proxy = new CglibProxyFactory(target).proxyCreator();
 8         // 调用目标对象方法
 9         String result2 = proxy.doSome();
10         System.out.println("输出结果:" + result2);
11     }
12 }

步骤5

执行测试类的main方法,执行结果如下:

输出结果:I COME FROM CHINA

 

通过以上的简单案例演示,相信你能很快的掌握代理模式的使用。

 

posted @ 2019-04-14 23:44  有梦想的小伙子~SY  阅读(183)  评论(0编辑  收藏  举报