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

    特点:字节码随用随创建,随用随加载
    作用:不修改源码的基础上对方法进行增强
    分类:

    基于接口的动态代理

    		   * 涉及的类:Proxy
    		   * 提供者:JDK官方
    		* 如何创建代理对象:
    				使用Proxy类中的newProxyInstance方法
    					参数:
    						* ClassLoader:类加载器
    								用于加载代理对象字节码,和被代理对象使用相同的类加载器。
    								写法是固定的
    						* Class[]:字节码数组
    								用于让代理对象和被代理对象有相同的方法
    								写法也是固定的
    						* InvocationHandler:用于提供增强的代码
    								一般是写一个该接口的实现类,一般是匿名内部类,但是不是必须的.
    								此接口的实现类都是谁用谁写
    		* 创建代理对象的要求:
    			被代理类最少实现一个接口
    

    实例
    先定义一个接口
    IProducer.java:

    package com.jiading.proxy;
    
    public interface IProducer {
        /*
        销售
         */
        public void saleProduct(Float money);
        /*
        售后
         */
        public void afterService(float money);
    }
    

    Producer.java

    package com.jiading.proxy;
    /*
    一个生产者
     */
    public class Producer implements IProducer{//代理必须是对实现了至少一个接口的对象进行
        /*
        销售
         */
        public void saleProduct(Float money){
            System.out.println("销售产品,并拿到钱:"+money);
        }
        /*
        售后
         */
        public void afterService(float money){
            System.out.println("提供售后服务并拿到钱:"+money);
        }
    
    }
    

    Client.java:

    package com.jiading.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /*
    模拟一个消费者
     */
    public class Client {
        public static void main(String[] args) {
            final Producer producer = new Producer();
            IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(),
                    new InvocationHandler() {
                        /*
                        执行被代理对象的任何接口方法都会结构该方法
                        方法参数的含义
                            proxy:代理对象的引用
                            method:当前执行的方法
                            args:当前执行方法所需的参数
                            return:和被代理对象有相同的返回值
                         */
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //提供增强的代码
                            Object returnValue = null;
                            //1.获取方法执行的参数
                            Float money = (Float) args[0];
                            //2.判断当前方法是不是销售
                            if ("saleProduct".equals(method.getName())) {
                                returnValue = method.invoke(producer, money*0.8f);
                            }
                            return returnValue;
                        }
                    });
            proxyProducer.saleProduct(10000f);
        }
    }
    

    基于子类的动态代理

    这种方法里类不需要继承接口,但是需要第三方库的支持

    • 涉及的类:Enhancer
      * 提供者:第三方cglib库
      * 如何创建代理对象:
      使用Enhancer类中的create方法
      参数:
      Class:字节码,用于指定被代理对象的字节码
      Callback:用于提供增强的代码
      一般写的是该接口的子接口的实现类,MethodInterceptor
      * 创建代理对象的要求:
      被代理类不能是最终类
      实例:
      pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>day03_proxy</artifactId>
        <version>1.0-SNAPSHOT</version>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>6</source>
                        <target>6</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>
    
    </dependencies>
    
    </project>
    

    Producer.java

    package com.jiading.cglib;
    
    import com.jiading.proxy.IProducer;
    
    /*
    一个生产者
     */
    public class Producer {//代理必须是对实现了至少一个接口的对象进行
        /*
        销售
         */
        public void saleProduct(Float money){
            System.out.println("销售产品,并拿到钱:"+money);
        }
        /*
        售后
         */
        public void afterService(float money){
            System.out.println("提供售后服务并拿到钱:"+money);
        }
    
    }
    

    Client.java

    package com.jiading.cglib;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /*
    模拟一个消费者
     */
    public class Client {
        public static void main(String[] args) {
            final Producer producer = new Producer();
            Producer proxyProducer= (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
                /*
                执行被代理对象的任何方法都会经过该方法
                proxy,method和args和基于接口的代理方法中得到参数是一样的
                proxyMethod是当前执行方法的代理对象
                 */
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    //提供增强的代码
                    Object returnValue = null;
                    //1.获取方法执行的参数
                    Float money = (Float) args[0];
                    //2.判断当前方法是不是销售
                    if ("saleProduct".equals(method.getName())) {
                        returnValue = method.invoke(producer, money * 0.8f);
                    }
                    return returnValue;
                }
            });
            proxyProducer.saleProduct(10000f);
        }
    }
    

    关于为什么这里在内部类中能用到的局部变量必须是final修饰的,可以看这篇文章:https://www.cnblogs.com/dolphin0520/p/3811445.html

  • 相关阅读:
    python二维数组切片
    [转载]MIPS常用指令及实例
    使用vim编程步骤
    数组指针和指针数组
    线程基础
    顶层const和底层const
    递归调用
    输出流
    C++代码规范
    I/O流
  • 原文地址:https://www.cnblogs.com/jiading/p/12343777.html
Copyright © 2011-2022 走看看