ToB企服应用市场:ToB评测及商务社交产业平台

标题: 代理模式实现 [打印本页]

作者: 圆咕噜咕噜    时间: 昨天 21:09
标题: 代理模式实现
一、概念:代理模式属于布局型设计模式。客户端不能直接访问一个对象,可以通过代理的圈外人来间接访问该对象,代理对象控制着对于原对象的访问,并答应在客户端访问对象的前后进行一些扩展和处理;这种设置模式称为代理模式;
2个点:
由代理对象去控制对原对象的访问(方法调用),客户端不直接对原对象进行访问,比如数据库的访问,不由Controller去控制;
在访问原对象时,可以有代理对象对原对象的功能(方法)进行扩展,比如访问数据库时,可以在代理对象内里进行开启事务和提交事务或回滚事务;
二、UML类图:

三、实现
1、静态代理实现
  1. /**
  2. * Subject
  3. */
  4. public interface IUserMapperInterface {
  5.     void save(String userName, String userNumber);
  6. }
复制代码
  1. /**
  2. * RealSubject
  3. */
  4. public class UserMapperInterfaceImpl implements IUserMapperInterface {
  5.     @Override
  6.     public void save(String userName, String userNumber) {
  7.         System.out.println("执行insert语句,保存数据,并返回成功!");
  8.     }
  9. }
复制代码
  1. /**
  2. * 代理类
  3. */
  4. public class UserMapperInterfaceProxy implements IUserMapperInterface {
  5.     private IUserMapperInterface userMapperInterface;
  6.     public UserMapperInterfaceProxy(IUserMapperInterface userMapperInterface) {
  7.         this.userMapperInterface = userMapperInterface;
  8.     }
  9.     @Override
  10.     public void save(String userName, String userNumber) {
  11.         System.out.println("开启事务~~~");
  12.         userMapperInterface.save(userName, userNumber);
  13.         System.out.println("提交事务");
  14.     }
  15. }
复制代码
  1. /**
  2. * 客户端
  3. */
  4. public class Client {
  5.     public static void main(String[] args) {
  6.         String userName = "user name";
  7.         String userNumber = "user number";
  8.         UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());
  9.         proxy.save(userName, userNumber);
  10.     }
  11. }
复制代码
优缺点:
长处:可以在不修改目标类的前提下,对目标类进行扩展
缺点:
代码冗余,代理对象实现了和目标对象一致的接口,产生了一些冗余接口;
一旦目标接口中增长了新的方法,那么代理对象和真实接口实现都须要修改代码才行;
2、动态代理的实现:
动态代理与静态代理的区别:
静态代理在类加载完经已经加载JVM中,而且如有其他对象须要加载,须要修改代理对象;
动态代理只有在运行的时间才会去加载目标类, 当须要加载其他对象的时间,不须要修改,也就是动态代理可以代理任何对象Object;
动态代理有两种实现方式:JDK动态代理,和CGLib动态代理

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. /**
  5. * 代理的工厂类
  6. */
  7. public class ProxyFactory {
  8.     //需要代理的目标类
  9.     private Object target;
  10.     public ProxyFactory(Object target) {
  11.         this.target = target;
  12.     }
  13.     public Object getTargetInstance() {
  14.         //Proxy是反射包下(java.lang.reflect)的一个代理类,通过这个类的newProxyInstance(新建代理对象实例)来动态的加载一个代理目标对象,并返回
  15.         //newProxyInstance方法需要传递三个参数,1、目标对象的类加载器, 2、目标对象实现的接口(如果有实现就有,没有实现就没有),3、目标对象需要执行的方法,相当于扩展静态代理中的那个save方法
  16.         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
  17.             //,目标对象被代理后需要执行的扩展方法,也有三个参数,1、目标对象,2、目标对象需要执行的方法实例,3、方法实例需要传递的参数
  18.             @Override
  19.             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  20.                 System.out.println("开启一个事务~!");
  21.                 //执行方法,执行的时候把目标对象和方法参数传递过去
  22.                 method.invoke(target, args);
  23.                 System.out.println("提交事务");
  24.                 //返回值是指目标执行的方法的返回值,如果没有就返回null,在静态代理中,目标方法save的返回值是void,因此这里返回null
  25.                 return null;
  26.             }
  27.         });
  28.     }
  29. }
复制代码
  1. /**
  2. * 客户端
  3. */
  4. public class Client {
  5.     public static void main(String[] args) {
  6.         String userName = "user name";
  7.         String userNumber = "user number";
  8.         //使用静态代理的模式实现代理,此时在类加载的时候就会创建该对象
  9.         UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());
  10.         proxy.save(userName, userNumber);
  11.         System.out.println("静态代理实现的类名:" + proxy.getClass().getName());
  12.         //使用动态代理的模式实现代理功能,在类加载的时候不会创建对象,在运行过程中才会去创建对象并调用对象 的方法
  13.         ProxyFactory proxyFactory = new ProxyFactory(new UserMapperInterfaceImpl());
  14.         IUserMapperInterface targetInstance = (IUserMapperInterface) proxyFactory.getTargetInstance();
  15.         targetInstance.save(userName, userNumber);
  16.         System.out.println("动态代理实现的类名:" + targetInstance.getClass().getName());
  17.     }
  18. }
复制代码

CGLib是一个第三方的代码生成类库,运行时在内存中生成一个子类继承目标对象,从而实现对目标对象的扩展;SpringAOP和Hibernate都是基于CGLib动态代理实现的,而CGlib又是通过封装ASM工具包去使用字节码的;
引入包:如果是Spring项目,则不须要单独引入,SpringCore内里已经包罗该包
  1. <dependency>
  2.             <groupId>cglib</groupId>
  3.             <artifactId>cglib</artifactId>
  4.             <version>3.3.0</version>
  5.         </dependency>
复制代码
目标类:
  1. /**
  2. * CGLib方式实现代理的目标类
  3. */
  4. public class CGLibTargetClass {
  5.     public void targetMethod(String userName, String userNumber) {
  6.         System.out.println("CGLibTargetClass targetMethod");
  7.         System.out.println("保存用户信息:username=" + userName + ",usernumber=" + userNumber);
  8.     }
  9. }
复制代码
代理类:实现MethodInterceptor接口,并重写interceptor方法,
  1. public class CGLibProxyIntercept implements MethodInterceptor {
  2.     @Override
  3.     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  4.         System.out.println("保存用户信息前开启事务");
  5.         System.out.println(objects.toString());
  6.         System.out.println(o.getClass().getName());
  7.         methodProxy.invokeSuper(o, objects);
  8.         System.out.println("保存用户信息后提交事务");
  9.         return o;
  10.     }
  11. }
复制代码
代理模式的总结:
由于CGlib采用的是继承目标类的方式去进行增强的,因此对于final类或方法是不能被继承的,无法使用CGlib的方式进行代理;
在jdk1.8后,现实上JDK动态代理比CGLib动态代理服从高,但JDK动态代理须要目标类实现一个接口,因此如果对象有实现接口,用JDK动态代理,没实现 用CGLib动态代理;
有缺点:
在客户端与目标对象之间起到中介作用,掩护目标对象
对目标对象进行扩展,将客户端与目标对象分离,解耦
增长体系复杂度




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4