• java23中设计模式之代理模式


    1.staicproxy ---静态代理

                          一).代理模式(proxy  pattern)  核心作用:

                                         1).通过代理,控制对对象的访问!

                                         2).可以详细控制访问某个对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理

                               二).应用场景

                                         1).安全代理:屏蔽对真实脚色真实访问

                                         2).远程代理: 通过代理类处理远程方法调用(RMI)

                                         3).延迟加载:先加载轻量级的代理对象,真正需要在加载真实对象

                               三).分类

                                         1).静态代理(静态定义代理类)

                                          2).动态生成代理类(动态生成代理类)

                                                 --JDK自带的动态代理

                                                --javaassist字节码操作库实现

                                                --Cglib    类库实现

                                               --ASM (底层使用指令,可维护性较差)

     

    package cn.sxt.service;
    
    public interface UserService {
        public void add();
        public void update();
        public void delete();
        public void search();
    }
    UserService
    package cn.sxt.service;
    
    public class UserServiceImpl implements UserService {
    
        @Override
        public void add() {
            //公共的业务----日志,安全,权限,缓存,事务等等
            //A.log();---分离的思想--纸质阅读器;osgi--java模块开发-spring--osgi
            System.out.println("增加用户");
        }
    
        @Override
        public void update() {
            
            System.out.println("修改用户");
        }    
    
        @Override
        public void delete() {
            System.out.println("删除用户");
        }
    
        @Override
        public void search() {
            System.out.println("查询用户");
        }
    }
    UserServiceImpl
    package cn.sxt.service;
    
    public class UserServiceProxy implements UserService{
        private UserService userService;
        public UserServiceProxy(UserService userService) {
            super();
            this.userService = userService;
        }
        
        public UserServiceProxy() {
            super();
        }
    
        @Override
        public void add() {
            log("add");
            userService.add();
        }
        @Override
        public void delete() {
            //日志,安全,缓存,事务,异常处理等
            log("delete");
            userService.delete();
        }
        @Override
        public void search() {
            log("search");
            userService.search();
        }
        public void update() {
            log("update");
            userService.update();
        }
        public void log(String methodName){
            System.out.println("执行"+methodName+"方法");
        }
        
    }
    UserServiceProxy
    package cn.sxt.service;
    
    public class Test {
     public static void main(String[] args) {
           UserServiceProxy proxy=new UserServiceProxy(new UserServiceImpl());  
           proxy.add();
           proxy.update();
           proxy.delete();
           proxy.search();
         
         
    }
    }
    /*执行add方法
    增加用户
    执行update方法
    修改用户
    执行delete方法
    删除用户
    执行search方法
    查询用户
    */
    Test

    2.dynamicproxy动态代理

                一)动态代理相比静态代理的优点

                          1).抽象角色中(接口)声明的 所以方法都被转移到调用处理器一个集中的地方处理,这样,我们可以更加灵活

                                和统一的处理众多的方法 

                           2)开发框架中应用场景:

                                    --stuts2 中拦截器的实现

                                    --数据库连接池关闭处理

                                   --hibernate 中延迟加载的实现

                                  -- mybatis中实现拦截器插件

                                   -- Aspect的实现

                                   --spring中AOP 的实现

                                            日志拦截和声明式实物处理

                                     --web  service   RMI  远程方法调用 

                           二).JDK动态代理中包含一个类和一个接口: 
                                        InvocationHandler接口: 
                                        public interface InvocationHandler { 
                                                       public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
                                          } 
                             参数说明: 
                                                  Object proxy:指被代理的对象。 
                                                  Method method:要调用的方法 
                                                  Object[] args:方法调用时所需要的参数 

                                  可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 

                          三).Proxy类: 
                                          Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
                                              public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
                                                       InvocationHandler h) 
                                                  throws IllegalArgumentException 
                                   参数说明: 
                                                ClassLoader loader:类加载器 
                                                Class<?>[] interfaces:得到全部的接口 
                                                InvocationHandler h:得到InvocationHandler接口的子类实例 

                             四).Ps:类加载器 
                                              在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
                                              Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
                                               Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jrelibext目录中的类; 
                                              AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

    version1

    package cn.sxt.dynamicproxy;
    
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    
    import cn.sxt.service.UserService;
    import cn.sxt.service.UserServiceImpl;
    
    public class Client {
        public static void main(String[] args) {
            System.out.println("userService+++++++++++++++++++++++++++++++");
            UserService userService = new UserServiceImpl();
            ProxyInovationHandler pih = new ProxyInovationHandler(userService);
            UserService proxy = (UserService)pih.getProxy();
            proxy.delete();
            
    
            System.out.println("list+++++++++++++++++++++++++++++++");
            ProxyInovationHandler ph1 = new ProxyInovationHandler(new ArrayList());
            List list = (List)ph1.getProxy();
            list.add(1);
            System.out.println(list.get(0));
        }
    }
    /*userService+++++++++++++++++++++++++++++++
    执行delete方法
    前置
    删除用户
    后置
    list+++++++++++++++++++++++++++++++
    执行add方法
    前置
    后置
    执行get方法
    前置
    后置
    1
    */
    Client
    package cn.sxt.dynamicproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyInovationHandler implements InvocationHandler{
        
        private Object target;//目标对象--真实对象
        
        
        public ProxyInovationHandler() {
            super();
        }
        
        public ProxyInovationHandler(Object i) {
            super();
            this.target = i;
        }
        
        public Object getProxy(){
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        /**
         * proxy是代理类
         * method 代理类的调用处理程序的方法对象
         * */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("执行"+method.getName()+"方法");
            System.out.println("前置");
            Object result = method.invoke(target, args);
            System.out.println("后置");
            return result;
        }
    }
    ProxyInovationHandler
    package cn.sxt.service;
    
    public interface UserService {
        public void add();
        public void update();
        public void delete();
        public void search();
    }
    UserService
    package cn.sxt.service;
    
    public class UserServiceImpl implements UserService {
    
        @Override
        public void add() {
            System.out.println("增加用户");
        }
    
        @Override
        public void update() {
            System.out.println("修改用户");
        }    
    
        @Override
        public void delete() {
            System.out.println("删除用户");
        }
    
        @Override
        public void search() {
            System.out.println("查询用户");
        }
    
    }
    UserServiceImpl

    version 2

    package com.ndqn.proxy;
    
    public interface Start {
        /**
         * 面谈
         */
        void confer();
        /**
         * 签合同
         */
        void signContract();
        /**
         * 订票
         */
        void bookTicket();
        /**
         * 唱歌
         */
        void sing();
        /**
         * 收钱
         */
        void collectMoney();    
        
    }
    star
    package com.ndqn.proxy;
    
    
    public class RealStar implements Start {
    
        @Override
        public void bookTicket() {
            System.out.println("RealStar.bookTicket()");
        }
    
        @Override
        public void collectMoney() {
            System.out.println("RealStar.collectMoney()");
        }
    
        @Override
        public void confer() {
            System.out.println("RealStar.confer()");
        }
    
        @Override
        public void signContract() {
            System.out.println("RealStar.signContract()");
        }
    
        @Override
        public void sing() {
            System.out.println("RealStar(周杰伦sing()");
        }
        
        
        
    }
    realstar
    package com.ndqn.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class StarHandle implements InvocationHandler {
         Start realStart;
         
        public StarHandle(Start realStart) {
            super();
            this.realStart = realStart;
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method,
                Object[] args) throws Throwable {
             Object object = null;
            
            System.out.println("真正的方法执行前!");
            System.out.println("面谈,签合同,预付款,订机票");
            
            if(method.getName().equals("sing")){
                object = method.invoke(realStart, args);
            }
            System.out.println("真正的方法执行后!");
            System.out.println("收尾款");
            return object;
        }
    
    }
    starHandle
    package com.ndqn.proxy;
    /**
     * 妯℃嫙鍔ㄦ�鐢熸垚鐨勪唬鐞嗙殑缁撴瀯
     * @author Administrator
     *
     */
    public class ProxyStar implements Start {
        
        StarHandle handler;
        
        public ProxyStar(StarHandle handler) {
            super();
            this.handler = handler;
        }
    
        public void bookTicket() {
    //        handler.invoke(this,当前方法 , args);
        }
    
        public void collectMoney() {
    //        handler.invoke(this,当前方法 , args);
        }
    
        public void confer() {
    //        handler.invoke(this,当前方法, args);
        }
    
        public void signContract() {
    //        handler.invoke(this,当前方法 , args);
        }
    
        public void sing() {
    //        handler.invoke(this,当前方法 , args);
        }
    
    }
    proxy动态生成的代理类
    package com.ndqn.proxy;
    
    
    import java.lang.reflect.Proxy;
    
    public class Client {
        public static void main(String[] args) {
            
            Start realStar = new RealStar();
            StarHandle handler = new StarHandle(realStar);
            
            Start proxy = (Start) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), 
                    new Class[]{Start.class}, handler);
            
            proxy.sing();
            
        }
        
    }
    client

    3.带有AOP的动态代理模式类图:

     

    从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。

    代码清单如下

    抽象主题或者接口:

    package com.yemaozi.proxy.dynamic_aop;
     
     public interface Subject {
         public void doSomething(String str);
        //...可以多个逻辑处理方法。。。
     }
    Subject
    package com.yemaozi.proxy.dynamic_aop;
      
      public class RealSubject implements Subject{
      
         public void doSomething(String str) {
              //do something...
              System.out.println("do something..." + str);
          }
      
     }
    RealSubject
    package com.yemaozi.proxy.dynamic_aop;
     
     //通知接口及定义、
     public interface IAdvice {
         public void exec();
     }
    IAdvice
    package com.yemaozi.proxy.dynamic_aop;
      public class BeforeAdvice implements IAdvice {
         //在被代理的方法前来执行,从而达到扩展功能。
       public void exec() {
             System.out.println("前置通知被执行!");
        }
     }
    BeforeAdvice
    package com.yemaozi.proxy.dynamic_aop;
      public class AfterAdvice implements IAdvice {
         
         //在被代理的方法后来执行,从而达到扩展功能。
         public void exec() {
             System.out.println("后置通知被执行!");
         }
     }
    AfterAdvice
    package com.yemaozi.proxy.dynamic_aop;
    
     import java.lang.reflect.InvocationHandler;
     import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
    
       //被代理的对象
         private Subject realSubject;
       //通过MyInvocationHandler的构造方法将被代理对象传递过来。
        public MyInvocationHandler(Subject realSubject){
            this.realSubject = realSubject;
         }
         //执行被代理类的方法。
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //在执行方法前,执行前置通知。
             IAdvice beforeAdvice = new BeforeAdvice();
             beforeAdvice.exec();
             Object result = method.invoke(this.realSubject, args);
            //在执行方法后,执行后置通知。
             IAdvice afterAdvice = new AfterAdvice();
             afterAdvice.exec();
            //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。
             return result;
         }
     
     }
    MyInvocationHandler
    package com.yemaozi.proxy.dynamic_aop;
    
     import java.lang.reflect.InvocationHandler;
     import java.lang.reflect.Proxy;
    
     public class DynamicProxy {
         
         /**
         * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
         * loader:
          *             一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。
        * interfaces:
          *             一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口,
         *             如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。
         *             即,查找出真是主题类的所实现的所有的接口。
          * handler:
          *             一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。
        *             该InvocationHandler与主题类有着关联。
         */
        public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
             @SuppressWarnings("unchecked")
             T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
            return t;
        }
     }
    DynamicProxy
    package com.yemaozi.proxy.dynamic_aop;
     
    import java.lang.reflect.InvocationHandler;
    
    public class AOPClient {
       
        public static void main(String[] args) {
             Subject realSubject = new RealSubject();
             InvocationHandler handler = new MyInvocationHandler(realSubject); 
             ClassLoader classLoader = realSubject.getClass().getClassLoader();
             Class<?>[] interfaces = realSubject.getClass().getInterfaces();
           Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
            proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
         }
     }
     
     执行结果:
     前置通知被执行!
     do something...这是一个Dynamic AOP示例!!!
    后置通知被执行!
    AOPClient

    动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。

    4. Cglib动态代理 
    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
    示例 

    package com.bdqn.ulist;
    /**
     *这个是没有实现接口的实现类
     * 
     * @author admin
     *
     */
    public class BookCadeImpl {
        public void add() {  
            System.out.println("This is add service");  
        }  
        public void delete(int id) {  
            System.out.println("This is delete service:delete " + id );  
        }  
    }
    BookCadeImpl
    package com.bdqn.ulist;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    /**
     * 使用cglib动态代理
     */
    public  class BookFacadeCglib implements MethodInterceptor {
        Object target;
        public Object getInstance(Object target){
            this.target=target;
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(this.target.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }
        //回调方法
        public Object intercept(Object obj, Method method, Object[] arg,
                MethodProxy proxy) throws Throwable {
            System.out.println("事务开始");
            Object ob=proxy.invokeSuper(obj, arg);
            System.out.println("事务结束");
            return ob;
        }
    
    }
    BookFacadeCglib
    package com.bdqn.ulist;
    
    import java.beans.Introspector;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    
    public class TestCglib {
     public static void main(String[] args) {
         BookFacadeCglib interceptor=new BookFacadeCglib();
         BookCadeImpl cadeImpl=(BookCadeImpl) interceptor.getInstance(new BookCadeImpl());
          cadeImpl.add(); 
          cadeImpl.delete(2);
    }
    }
    TestCglib

  • 相关阅读:
    JQuery Ajax 在asp.net中使用总结
    直接拿来用!最火的Android开源项目(一)
    专访邓凡平:Android开发路上的快速学习之道
    C/C++使用心得:enum与int的相互转换
    学习汇编的第一步
    《汇编程序》王爽实验9的解法(显示的问题)
    《汇编程序》王爽实验10.2的解法
    GDB调试精粹及使用实例
    aptget 使用详解
    《汇编程序》王爽实验10.3的解法
  • 原文地址:https://www.cnblogs.com/ou-pc/p/7668206.html
Copyright © 2020-2023  润新知