zoukankan      html  css  js  c++  java
  • Java-动态代理技术

    1.程序中的代理

       为具有相同接口的目标类的各个方法,添加一些系统功能,如日志,异常处理,计算方法运行的

       时间,事务管理等等,都可以交给另一个类去实现这些功能,该类称为代理类。

       注意:为了让代理类共享目标类中的各个方法,可以让代理类实现和目标类相同的接口。

    复制代码
      public class AProxy {
        //AProxy类为A的代理类,可以计算sayHi方法的运行时间
        public  void getTime()
        {
            //方法开始前时间
             new A().sayHi();
            //方法结束后时间
        }
    }
    class A
    {
        void sayHi()
        {
            System.out.println("hi,everyone!");
        }
    }
    复制代码

    2.代理架构图

      

       它采用工厂模式和配置文件的方式进行管理,这样就不需要修改客户端程序,通过

       配置文件指定使用目标类,还是代理类。这样做添加/去掉系统功能变得简单。

       当我们需要测试系统的性能时,可以使用代理类,客户要使用时可以使用目标类

    3.AOP(Aspect oriented program)

       交叉业务:要处理不同层面的业务(service),称为交叉业务,如安全,事务,日志等。

                                      安全       事务         日志
        StudentService  ------|----------|------------|-------------
        CourseService   ------|----------|------------|-------------
        MiscService       ------|----------|------------|-------------

       用具体的程序代码描述交叉业务:
         method1         method2          method3
         {                      {                       {
           ------------------------------------------------------切面
              ....            ....              ......
           ------------------------------------------------------切面
          }                       }                       }

       面向方面的编程(简称AOP),AOP的目标就是要使交叉业务模块化。

       可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
           ------------------------------------------------------切面
           func1         func2            func3
            {             {                {
              ....            ....              ......
             }             }                }
          ------------------------------------------------------切面

        这里就是使用代理技术解决这种问题,代理是实现AOP功能的核心和关键技术。
    4.动态代理技术

    •   要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!
    •   JVM提供了动态代理类(Proxy)。即可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类。这里是仅指具有接口的代理类和目标类。
    •   对于没有接口的目标类,CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。

       代理方法中的有如下四个位置加上系统功能代码:

         1.在调用目标方法之前
         2.在调用目标方法之后
         3.在调用目标方法前后
         4.在处理目标方法异常的catch块中

    复制代码
    class proxy{
        void sayHello(){
            ………//1
            try{
                target.sayHello();
            }catch(Exception e){
                ………//4
            }
            …………//2
        }
    }
    复制代码

    5.Proxy(代理类)

          |-java.lang.reflect.Proxy

          Proxy提供了创建动态代理类和实例的静态方法,它也是这些创建出来类的超(父)类。

          构造方法:

                protected  Proxy(InvocationHandler  h);//使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例

          成员方法:

                static Class<?> getProxyClass(ClassLoader loader,Class<?> interfaces);//创建一个具有接口的动态代理类。

                static Object newProxyInstance (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);//返回一个代理类实例对象

      创建代理类及其实例对象:

      法一:先创建代理类,再用代理类的构造方法创建实例对象

    复制代码
    public static void main(String[] args) {
            // 获得一个集合接口的代理类,为其指定接口和类加载器
            //通常loader,interface是一样的字节码产生的
            Class  clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
            System.out.println(clazzProxy1.getName());
            //创建一个代理类实例
            //注意:clazzProxy1.newInstance()调用的是它的无参构造方法创建实例,但是它没有无参的构造方法
            //通过有参构造方法创建实例
            Constructor ct=clazzProxy1.getConstructor(InvocationHandler.class);
            class MyinvocationHandler implements InvocationHandler
            {
                 @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                     return null;
                }
             }
            Collection proxy1=(Collection) ct.newInstance(new MyinvocationHandler());
         }}
    复制代码

       法二:用new方法直接创建代理类实例对象

    复制代码
    Object target=new Object ();
    Object proxy1=Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    // TODO Auto-generated method stub
    return null;
    }
    });
    
    Class<?> []cs={Collection.class};
    Collection proxy3=(Collection)Proxy.newProxyInstance
            (Collection.class.getClassLoader(),
              cs,new MyinvocationHandler());
    Collection proxy4=(Collection)Proxy.newProxyInstance
            (Collection.class.getClassLoader(),
             new Class[] {Collection.class},
             new MyinvocationHandler());
    复制代码

    6.InvocationHandler(接口)

       成员方法:

            Object invoke(Object proxy, Method method, Object[] args);//在代理实例上处理方法调用并返回结果。

            事实上,Proxy代理类对象调用(该接口上的)方法时,其实是去调用了handler的

            invoke方法。对于不是该接口上的方法,如getClass(),则调用它本身的,不用委托handler去调用invoke方法。

    7.代理类的模式

       以面向对象的思想处理AOP(面向方面编程)的业务,即在实现代理的系统功能时,将目标类对象和接口(该接口通常以实现接口某个类的方式传入,实现接口里的方法(系统功能)的类)作为参数传入一个要实现系统功能的方法中。

    复制代码
            ArrayList al=new ArrayList();
            Collection proxy4=(Collection)getProxy(al,new Myadvice());
            proxy4.add("hq");
        //以下是封装了实现代理功能的一个方法
        //参数:目标类对象,和接口(实现代理功能的类,类里有实现功能的方法),该接口通常以实现接口某个类的方式传入。
        private static Object getProxy(final Object target,final interfaceAdvice advice) {
             Object proxy=Proxy.newProxyInstance
                    (target.getClass().getClassLoader(),
                     target.getClass().getInterfaces(),
                     new InvocationHandler(){
                        
                        @Override
                        public Object invoke(Object proxy, Method method,
                                Object[] args) throws Throwable {
                             advice.beforeMethod(method);
                             Object obj=method.invoke(target, args);
                             advice.afterMethod(method);
                             return obj;
                        }
                    });
             return proxy;
        }
    复制代码

    8.实现AOP功能的封装与配置

    工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例 对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的 getProxy方法返回的对象。
    BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
        #xxx=java.util.ArrayList
        xxx=cn.itcast.ProxyFactoryBean
        xxx.target=java.util.ArrayList
        xxx.advice=cn.itcast.MyAdvice
    ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息?
    目标:target
    通知:advice
    编写客户端应用:
    编写实现Advice接口的类和在配置文件中进行配置
    调用BeanFactory获取对象。

    摘自:

    http://www.cnblogs.com/beyondbycyx/p/4314536.html

  • 相关阅读:
    Codeforces
    Codeforces
    SCUT
    Codeforces
    Codeforces
    poj 2229 Sumsets(类似于n的m划分)
    poj 1742 Coins(多重背包)
    hdu 2159FATE(完全背包)
    NOIP 普及组 2014 比例简化
    2018.10.2浪在ACM 集训队第三次测试赛
  • 原文地址:https://www.cnblogs.com/tyhJava/p/5503308.html
Copyright © 2011-2022 走看看