zoukankan      html  css  js  c++  java
  • 动态代理

    增强的手段
    1、继承
    *被增强对象不能变
    *增强内容不能变
    2.装饰者模式
    *被增强对象可变
    *但增强内容不可变
    3.动态代理
    *被增强对象可变
    *增强内容可变

    首先一个方法:

    Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces,invocationHandler h);

    1、方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!

    参数:

    1、ClassLoader:类加载器
    它是用来加载类的,把.class文件加载到内存形成Class对象!
    2、Class[] interfaces:指定要执行的接口
    3、invocationHandler:代理对象的所有方法(个别方法不执行)都会调用InvocationHandler的invoke方法

    第一个测试类:

    package com.itcast.demo1;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.junit.Test;
    
    public class Demo1 {
        @Test
        public void fun1(){
            /*
             * 三大参数
             * 1.ClassLoader
             * 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象!
             * 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader
             *
             * 2.Class[] interfaces
             * 它是要实现的接口们
             * 
             * 3.InvocationHandler
             * 它是调用处理器
             * 敷衍它
             * 
             * 代理对象的所有方法都是调用invocationHandler的invoke方法
             */
            ClassLoader loader=this.getClass().getClassLoader();
            InvocationHandler h=new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    System.out.println("你好,动态代理!");
                    return null;
                }
            };
            //使用三大参数创建代理对象
            Object o=Proxy.newProxyInstance(loader, new Class[]{A.class,B.class}, h);
            
            //强转成A和B类型,成功了!
            A a=(A) o;
            B b=(B) o;
            a.a();
            b.b();
            a.aa();
            b.bb();
            System.out.println(a.getClass().getName());
            
        }
    }
    interface A{
        public void a();
        public void aa();
    }
    interface B{
        public void b();
        public void bb();
    }

    证实几点:

      1、该方法生成了实现指定接口的代理对象。

      2、代理类的几乎所有方法的执行都是调用invocation的invoke方法。

      3、类加载器使用this.getClass().getClassLoader()得到。

    动态代理的作用
    最终是学习AOP(面向切面编程),它与装饰者模式有点相似,它比装饰者模式还要灵活!

    方法:

    public Object invoke(Object proxy,Method method,Object[] args)

    这个invoke方法什么时候被调用!
    1、在代理对象呗创建时?错误的
    2、在调用代理对象所实现接口中的方法时?正确的!

    *Object proxy:当前对象,即代理对象!在调用谁的方法!
    *Method method:当前被调用的方法(目标方法)
    *Object[] args:实参!

    实现

    (*被增强对象可变*但增强内容不可变):

    package com.itcast.demo2;
    //服务员
    public interface Waiter {
        //服务
        public void server();
    
    }
    
    package com.itcast.demo2;
    
    public class ManWaiter implements Waiter {
    
        @Override
        public void server() {
            System.out.println("服务中!");
        }
    
    }
    
    package com.itcast.demo2;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.junit.Test;
    /**
     * 我们必须要掌握的是当前这个案例!
     * @author Administrator
     *
     */
    public class Demo2 {
    
        @Test
        public void fun1(){
            Waiter manWaiter=new ManWaiter();
            /*
             * 给出三个参数,来调用方法得到代理对象
             */
            ClassLoader loader=this.getClass().getClassLoader();
            Class[] interfaces={Waiter.class};
            InvocationHandler h=new WaitInvocationHanlder(manWaiter); //被增强的目标对象
            Waiter waiter=(Waiter) Proxy.newProxyInstance(loader, interfaces, h);
            
            waiter.server();//前面加你好,后面加再见
        }
        
    }
    class WaitInvocationHanlder implements InvocationHandler{
        private Waiter waiter;//目标对象
        public WaitInvocationHanlder(Waiter waiter){
            this.setWaiter(waiter);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("你好!");
            this.waiter.server();//调用目标对象的方法
            System.out.println("再见!");
            return null;//return 的值是执行的方法的返回值,这个方法的proxy表示的是本代理对象,所以不能使用method.invoke(proxy,args).这样会走死循环。
        }
    
        public void setWaiter(Waiter waiter) {
            this.waiter = waiter;
        }
    
        public Waiter getWaiter() {
            return waiter;
        }
        
    }

    使用工厂模式,实现增强内容也可变。

    目标对象:被增强的对象
    代理对象:需要增强的对象,
    目标:

      执行前增强

      执行后增强

    package com.itcast.demo3;
    /**
     * 前置增强
     */
    public interface BeforeAdvice {
        public void before();
    
    }
    
    package com.itcast.demo3;
    /*
     * 后置增强
     */
    public interface AfterAdvice {
        
        public void after();
    }
    
    package com.itcast.demo3;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 它用来生成代理对象
     * 它需要所有的参数
     *     *目标对象
     *  *增强
     */
    /**
     * 1、创建代理工厂
     * 2、改工厂设置三样东西:
     *     *目标对象setTargetObject
     *     *前置增强:setBeforeAdvice
     *     *后置增强:setAfterAdvice
     * 3、调用createProxy()得到代理对象
     *     *执行代理对象方法时:
     *         执行BeforeAdvice的before()
     *         目标对象的目标方法
     *         执行AfterAdvice的after()
     */
    public class ProxyFactory {
        private Object targetObject;//目标对象
        private BeforeAdvice beforeAdvice;//前置增强
        private AfterAdvice afterAdvice;//后置增强
        public Object getTargetObject() {
            return targetObject;
        }
        
        /**
         * 用来生成代理对象
         * @return
         */
        public Object createProxy(){
            /*
             * 给出三大参数
             */
            ClassLoader loader=this.getClass().getClassLoader();
            Class[] interfaces=targetObject.getClass().getInterfaces();
            InvocationHandler h=new InvocationHandler() {
                
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    /*
                     * 在调用代理对象的方法时,执行这里的内容
                     */
                    //执行前置增强
                    if(beforeAdvice!=null){
                        beforeAdvice.before();
                    }
                Object result=method.invoke(targetObject, args);//执行目标对象的目标方法
                    //执行后置增强
                    if(afterAdvice!=null){
                        afterAdvice.after();
                    }
                    //返回目标对象中的返回值
                    return result;
                }
            };
            
            //得到代理对象
            Object obj=Proxy.newProxyInstance(loader, interfaces, h);
            
            //返回代理
            return obj;
        }
        
        
        
        public void setTargetObject(Object targetObject) {
            this.targetObject = targetObject;
        }
        public BeforeAdvice getBeforeAdvice() {
            return beforeAdvice;
        }
        public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
            this.beforeAdvice = beforeAdvice;
        }
        public AfterAdvice getAfterAdvice() {
            return afterAdvice;
        }
        public void setAfterAdvice(AfterAdvice afterAdvice) {
            this.afterAdvice = afterAdvice;
        }
        
    
    }

    主要代码就这些:

    这里实现增强内容可变的方法是代理对象的执行体令它是可变的,所以使用工厂进行创建,进行了一些包装操作。我们必须透彻理解如何进行的增强,增强的步骤等。

    难点在于:

      1、思路。明确知道自己需要什么怎么办。

      2、proxy中的invoke方法的书写。

  • 相关阅读:
    Windows-快速预览文件-QuickLook
    Chrome简洁高效管理下载项
    有Bug?你的代码神兽选对了吗
    保护视力-刻不容缓
    一次看懂 Https 证书认证
    Web前端助手-功能丰富的Chrome插件
    Chrome自动格式化Json输出
    网络爬虫
    彻底搞懂Cookie,Session,Token三者的区别
    Redis内存满了的解决办法
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/5908533.html
Copyright © 2011-2022 走看看