zoukankan      html  css  js  c++  java
  • java 编程基础 Class对象 反射:动态代理 和AOP:java.lang.reflect.Proxy:(Proxy.newProxyInstance(newProxyInstance​(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h))

    为什么我们使用动态代理

    静态代理会让类变多了,多了代理类,工作量变大了,且不易扩展。比如我们上节课的例子,要实现不同的扩展方法就要编写不同的代理类,非常麻烦。
     

    Proxy类的使用规则

    Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态生成实现类,就可以使用 Proxy 来创建动态代理类。如果需要为一个或多个接口动态地创建实例,也可以使 Proxy 来创建动态代理实例。
    Proxy提供了如下两个方法来创建动态代理类和动态代理实例:
    • static Class getProxyClass(ClassLoader loader, Class... interfaces): 创建一个动态代理类所对应的 Class对象,该代理类将实现interfaces 所指定的多个接口。第一个 ClassLoader 参数指定生成动态代理类的类加载器。(已过时)
    • static Object newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h): 直接创建一个动态代理对象,代理对象的实现类实现了 interfaces 指定的系列接口 ,执行代理对象的每一个方法时都会被替换执行InvocationHandler 对象的 invoke 方法。
    用实例来说明一下:
    1,我们先定义一个接口:
    package com.zmd.dynamicProxy;
    
    /**
     * @ClassName Person
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/16.
     */
    public interface Person {
        void walk();
        void sayHello(String name);
    }

    2,定义自定义的InvocationHandler 继承InvocationHandler:

    package com.zmd.dynamicProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * @ClassName MyInvocationHandler
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/16.
     */
    public class MyInvocationHandler implements InvocationHandler {
        @Override
        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            System.out.println("=======正在执行方法:"+ method.getName());
            if (objects != null) {
                System.out.println("下面为传入的参数:");
                for (Object arg : objects) {
                    System.out.println(arg);
                }
            } else {
                System.out.println("没有传入任何的参数");
            }
            return null;
        }
    }

    3,调用测试:

    package com.zmd.dynamicProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    /**
     * @ClassName MyInvocationTest
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/16.
     */
    public class MyInvocationTest {
        public static void main(String[] args) {
            InvocationHandler invocationHandler = new MyInvocationHandler();
            Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class},invocationHandler);
            person.walk();
            person.sayHello("美女");
        }
    }

    动态代理和AOP

    根据前面介绍的 Proxy和InvocationHandler,实在很难看出这种动态代理的优势 下面介绍一种更实用的动态代理机制。
    开发实际应用的软件系统时,通常会存在相同代码段重复出现的情况,在这种情况下,对于许多刚开始从事软件开发的人而言,他们的做法是:选中那些代码,Ctrl+C、Ctrl+V,如果仅仅从软件功能上来看,他们确实已经完成了软件开发。但是万一这段相同的逻辑需要改动呢?是不是要改很多地方呢?
    用看电影举例:
    1,首先创建电影功能接口:
     
    package com.zmd.dynamicProxy.movieExample;
    
    public interface Movie {
        void play();
    }
    2,创建Movie的实现类(电影):
    package com.zmd.dynamicProxy.movieExample;
    
    public class ZhanlangMovie implements Movie {
    
        @Override
        public void play() {
            System.out.println("战狼,播放中...");
        }
    }

    3,创建代理用的工具类,比如放电影之前和之后要干的事儿

    package com.zmd.dynamicProxy.movieExample;
    
    public class MovieUtil {
        //play之前的方法
        public static void before(){
            System.out.println("PLAY 之前....");
        }
        //play之前的方法
        public static void after(){
            System.out.println("PLAY 之后....");
        }
    }

    4,创建自定义代理类继承InvocationHandler,使用工具类为要代理接口实现类增加效果

    package com.zmd.dynamicProxy.movieExample;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
        private Movie movie;
    
        public MyInvocationHandler(Movie movie) {
            this.movie = movie;
        }
    
        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
            //先调用工具类的方法(加广告)
            MovieUtil.before();
            //执行被包装的类的方法
            Object result = method.invoke(movie, args);
            //再调用工具类的方法(还是广告)
            MovieUtil.after();
            return result; //被包装的类的方法返回什么,这里也返回什么
        }
    }

    5,利用代理类封装功能类,传入被代理的接口实现类(电影),返回真正给用户的电影

    package com.zmd.dynamicProxy.movieExample;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    public class MovieFactory {
        public static Movie getFactoryMovie(Movie movie){
            InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie);
            Movie movie1 = (Movie) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler);
            return movie1;
        }
    }

    6、使用代理类

    package com.zmd.dynamicProxy.movieExample;
    
    public class FactoryMovieTest {
        public static void main(String[] args) {
            Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie());
            zhanlang.play();
        }
    }

    PLAY 之前....
    战狼,播放中...
    PLAY 之后....

     带泛型的代理,代理一切...

    代理类  MyInvocationHandler.java 

    package com.zmd.dynamicProxy.movieExample;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * @ClassName MyInvocationHandler
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/17.
     */
    public class MyInvocationHandler <T> implements InvocationHandler   {
        private T movie;
    
        public MyInvocationHandler(T movie) {
            this.movie = movie;
        }
    
        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
            //先调用工具类的方法(加广告)
            MovieUtil.before();
            //执行被包装的类的方法
            Object result = method.invoke(movie, args);
            //再调用工具类的方法(还是广告)
            MovieUtil.after();
            return result;
        }
    }

    使用代理做的包装工具类 MovieFactory.java

    package com.zmd.dynamicProxy.movieExample;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    /**
     * @ClassName MovieFactory
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/17.
     */
    public class MovieFactory<T> {
        public static <T> T getFactoryMovie(T movie){
            InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie);
            T movie1 = (T) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler);
            return movie1;
        }
    }

    测试使用

    音乐接口和实现类

    package com.zmd.dynamicProxy.movieExample;
    
    public interface Music {
        void play();
    }
    package com.zmd.dynamicProxy.movieExample;
    
    public class YueLiangZhiShang implements Music {
        @Override
        public void play() {
            System.out.println("我在遥望,月亮之上...");
        }
    }

    测试类

    package com.zmd.dynamicProxy.movieExample;
    
    /**
     * @ClassName FactoryMovieTest
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/17.
     */
    public class FactoryMovieTest {
        public static void main(String[] args) {
            Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie());
            zhanlang.play();
            Music yueliangzhishang = MovieFactory.getFactoryMovie(new YueLiangZhiShang());
            yueliangzhishang.play();
        }
    }

    PLAY 之前....
    战狼,播放中...
    PLAY 之后....
    PLAY 之前....
    我在遥望,月亮之上...
    PLAY 之后....

  • 相关阅读:
    firebird database (快速入門)
    firebird的数据类型(datatype)
    通过ASP.NET获取URL地址方法
    FIREBIRD使用经验总结
    C# Append a host header to a website in IIS by code
    Ubuntu 9.04 下载镜像地址
    Firebird如何防止空值扩散
    Tmail: 开源邮件服务器软件包
    Firebird中的NULL
    本地数据源:使用firebird数据库
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/14775210.html
Copyright © 2011-2022 走看看