【设计模式】动态代理设计模式

动态代理
假如有一个Dog类,该类有eat()和sleep()方法;由该类创建了一个dog对象,现在有一个需求,想知道sleep执行了多长时间,该如何实现这个需求呢?
可以使用动态代理来实现这个需求。
关于动态代理的两个重要的类:
1.Proxy:构造动态代理对象的方法Proxy:构造动态代理对象的方法
          public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException
          loader - 定义代理类的类加载器
          interfaces - 代理类要实现的接口列表
          h - 指派方法调用的调用处理程序    
         
2.InvocationHandler:只有一个invoke方法:
          Object invoke(Object proxy,
                      Method method,
                      Object[] args)
                      throws Throwable
               proxy - 在其上调用方法的代理实例
               method - 对应于在代理实例上调用的接口方法的 Method 实例。
               args - 包含传入代理实例上方法调用的参数值的对象数组.

为了实现计算dog的sleep时间,需要抽象出一个Animal接口,代码为:
Animal.java
代码为:
public  interface Animal {
      public  void eat();
      public  void sleep();
}

Dog类实现Animal接口:
Dog.java
代码为:
public  class Dog implements Animal {
      public  void eat() {
          System.  out.println("狗狗正在吃东西。。" );
     }

      public  void sleep() {
          System.  out.println("狗狗正在睡觉觉。。" );
            try {
              Thread. sleep(1000);
          }  catch (InterruptedException e) {
              e.printStackTrace();
          }
     }
}

封装了自己需求的Advice接口:
Advice.java:

public  interface Advice {

      void  beforeMethod(Method method);

      void  afterMethod(Method method);
}


MyAdvice.java:

public  class MyAdvice implements Advice {
      long  beginTime=0;
      long  endTime=0;
      public  void afterMethod(Method method) {
            endTime=System. currentTimeMillis();
          System.  out.println(method.getName()+"方法执行后。。共睡了:" +(endTime -beginTime )/1000+"秒" );
     }

      public  void beforeMethod(Method method) {
            beginTime=System.currentTimeMillis(); 
          System.  out.println(method.getName()+"方法执行前。。。" );
     }
}



抽象一个返回某个实例target的代理对象的方法:
public  class ProxyDemo {

      /**
      * 获取某个target对象的代理对象,并加入自己想要操作的代码,我们称之为advice;
      *
      *  @param target
      *            要去代理的对象;
      *  @param advice
      *            封装了自己需求的对象;
      *  @return target的代理对象;
      */
      public  static Object getProxy(final Object target, final Advice advice) {
            return Proxy.newProxyInstance(
                   target.getClass().getClassLoader(),
                   target.getClass().getInterfaces(),  
                   new  InvocationHandler() {
                          public Object invoke(Object proxy, Method method,
                                  Object[] args)  throws Throwable {

                               if (method.getName().equals("sleep" )) {// 如果调用的方法是sleep方法;
                                  advice.beforeMethod(method);  // 调用真正的方法前,执行一些操作
                                  Object retValue = method.invoke(target, args);
                                  advice.afterMethod(method);  // 调用方法后,执行一些操作。
                                    return retValue;
                             }  else {// 调用的是其他方法
                                  Object retValue = method.invoke(target, args);
                                    return retValue;
                             }

                        }

                   });

     }

      public  static void main(String[] args) {
          Animal dog =  new Dog();
          Advice advice =  new MyAdvice();
          Animal proxyDog = (Animal) getProxy(dog, advice);

          proxyDog.eat();
          proxyDog.sleep();
            /*
           * 每次调用proxyDog对象的方法,都会去执行invoke方法,因此可以在invoke方法里对方法的执行实现控制,
           * 如如果调用的是sleep方法,那么就加入自己的一些想法,是其他方法则放行,相当于起到了过滤器的左右,这比过滤器实现了更细微程度的控制。
           */
     }
}

================================
例子二.动态代理更为简单的实现:
      //动态代理,针对的是一个已经存在的对象,需要对这个对象的特定的一些方法做改造;例如,改造狗叫的方法;
            final Dog dog = new Dog();//Dog有吃和叫这两个方法;
          Animal proxy = (Animal) Proxy.newProxyInstance(dog.getClass().getClassLoader(), dog.getClass().getInterfaces()
              ,  new InvocationHandler(){

                     public Object invoke(Object proxy, Method method, Object[] args)
                               throws Throwable {
                          if("叫" .equals(method.getName())){
                             System.  out.println("代理狗哈哈哈哈的叫。。。。。" );
                               return null ;
                        }  else{
                               return method.invoke(dog, args);
                        }
                   }
          });
          
          proxy.吃();
          proxy.叫();

====================================
动态代理例子三
使用hibernate进行操作数据库,保存数据时,需要开启事务,现将开启事务的操作交由动态代理对象来做。 

创建一个对象的代理对象,需要三个参数:
          public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
自己写一个handler,在handler的invoke方法中,实现开启事务和提交事务。

Classes为要保存到数据库的实体类。

完整代码:
public  class HibernateUtils {
      public  static SessionFactory sessionFactory;
      static {
          Configuration configuration =  new Configuration();
          configuration.configure();
            sessionFactory = configuration.buildSessionFactory();
     }
}
============================================
public  class MyTransaction extends HibernateUtils{
      private  Transaction transaction;
      public  void beginTransaction(){
            this.transaction = sessionFactory.getCurrentSession().beginTransaction();
     }
      public  void commit(){
            this.transaction .commit ();
     }
}
============================================
public  interface ClassesDao {
      public  void saveClasses(Classes classes);
     
      public  void updateClasses(Classes classes);
     
      public  List<Classes> getClasses();
}
============================================
public  class ClassesDaoImpl extends HibernateUtils implements ClassesDao{

      @Override
      public  void saveClasses(Classes classes) {
            sessionFactory.getCurrentSession().save(classes);
     }

      @Override
      public  List<Classes> getClasses() {
            return sessionFactory .getCurrentSession().createQuery("from Classes").list();
     }

      @Override
      public  void updateClasses(Classes classes) {
            sessionFactory.getCurrentSession().update(classes);
     }

}
============================================
/**
 * 自己定义一个handler来完成事务操作。
 * 1、引入目标类
 * 2、引入事务
 * 3、完成invoke方法
 */
public  class ClassesDaoInterceptor implements InvocationHandler{
     
      private  ClassesDao target;
     
      private  MyTransaction myTransaction;
     
      public  ClassesDaoInterceptor(ClassesDao target,MyTransaction myTransaction){
            this.target = target;
            this.myTransaction = myTransaction;
     }

      @Override
      public  Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            /**
           * 1、开启事务
           * 2、调用目标类的方法
           * 3、提交事务
           */
            if(method.getName().equals("saveClasses" )||
                   method.getName().equals(  "updateClasses")){
                //开启事务,调用方法,提交事务
                this.myTransaction .beginTransaction();//通知
              method.invoke(  this.target , args);//目标方法
                this.myTransaction .commit();
              
          }  else{
              method.invoke(  this.target , args);
          }
            return null ;
     }

}
============================================
/**
 * 注意的点
 *    1、代理对象的方法体的内容就是拦截器 中invoke方法体的内容
 *    2、在客户端,用代理对象调用方法的时候进去了invoke方法
 */
public  class ClassesDaoTest {
      @Test
      public  void testSaveClasses(){
            //目标类
          ClassesDao target =  new ClassesDaoImpl();
          MyTransaction myTransaction =  new MyTransaction();
          ClassesDaoInterceptor interceptor =  new ClassesDaoInterceptor(target, myTransaction);
            /**
           * 获取动态代理对象
           * 1、目标类的类加载器
           * 2、目标类实现的所有的接口
           * 3、拦截器
           */
          ClassesDao targetProxy = (ClassesDao) Proxy.newProxyInstance(
                   target.getClass().getClassLoader(),
                   target.getClass().getInterfaces(),
                   interceptor);
          
          Classes classes =  new Classes();
          classes.setCname(  "多对多");
          
          targetProxy.saveClasses(classes);
     }
}
============================================



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值