【Java高级程序设计学习笔记】深入理解jdk动态代理

java的设计模式中有一项设计模式叫做代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。代理又分为静态代理和动态代理,静态代理就是针对每个被代理对象写一个代理类,操作不够优雅;动态代理,可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮你完成了。

1.动态代理简介

动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类。换句话说,动态代理是一种创建java对象的能力,让你不用创建代理类(jdk内部创建),就能创建代理类对象。

【Java高级程序设计学习笔记】深入理解jdk动态代理_第1张图片

 2.动态代理的实现

  1. jdk动态代理 :使用java反射包中的类和接口实现动态代理的功能。

   反射包java.lang.reflect中有三个类:InvocationHandler、 Method、Prooxy。

  2. cglib动态代理(了解):第三方工具库,原理是继承目标类,创建它的子类,在子类中重写父类方法,实现功能的修改。所以要求目标类和方法不能是final

  cglib要求目标类比较宽松,只要能继承就可。cglib在很多的框架中使用。

 

3. jdk动态代理

3.1 反射

Method类,标识方法,类中的方法,通过Method可以执行某个方法。

package practice.Chapter7;

public interface HelloService {
    // 和name打招呼
    public void sayHello(String name);
}

package practice.Chapter7;

public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("hello: " + name);
    }
}

package practice.Chapter7;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

package practice.Chapter7;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class demo {
    public static void main(String[] args) {
//        HelloService service = new HelloServiceImpl();
//        service.sayHello("张三");
        //使用反射机制执行该方法
        HelloService target = new HelloServiceImpl();
        Class clazz = target.getClass();
        Method method = null;
        try {
            method = clazz.getMethod("sayHello", String.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            method.invoke(target, "张三");
            // invoke是Method类中的一个方法,表示执行方法的调用
            // 参数:1、Object 对象,要执行这个对象的方法 2. Object...args,方法执行的参数
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

3.2 jdk动态代理的实现

 

反射包java.lang.reflect中有三个类:InvocationHandler、 Method、Prooxy。、

1)InvocationHandler接口(调用处理器):表示你的代理要干什么。就一个方法invoke()

     invoke():表示代理对象要执行的功能代码。代理类完成的功能要写在invoke()方法中。

     代理类完成的功能:1调用目标方法,执行目标方法的功能

                  2功能增强,在目标方法调用时,增加功能

   方法原型:

   参数:Object proxy :jdk创建的代理对象,无需赋值。

              Method method: 目标类中的方法,jdk提供method对象

              Object[] args: 目标类中方法的参数,jdk提供的

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

如何使用?

  1. 创建类实现接口InvocationHandler
  2. 重写invoke()方法,把原来静态代理中的代理类要完成的功能写在这。

2) Method类:(反射)表示方法的,确切的说就是目标类中的方法。

      作用:通过Method可以执行某个目标类的发不能发,Method.invoke(目标对象,方法参 数)

     说明:method.invoke() 就是用来执行目标方法的等同于静态代理中:向厂家发送订单,告诉厂家,我买了u盘,厂家发货

3)Proxy类:核心的对象,创建代理对象。之前创建对象new 类的构造方法,现在我们使用Proxy类的方法,代替new的使用,代替new的使用。

   方法:静态方法 newProxyInstance()

   作用:创建代理对象,等同于静态代理中的new 构造方法()的语句。

   参数:

   1.ClassLoader loader:类加载器,负责向内存中加载对象的。使用反射获取对象的ClassLoader。如:类a  a.getClass().getClassLoader(),目标对象的类加载器

     2. Class[ ] interfaces:接口,目标对象所实现的接口,也是反射获取的。

     3. InvocationHandler h:我们自己写的,代理类要完成的功能。

   返回值:目标对象的代理对象

public static Object newProxyInstance(ClassLoader loader,
                                       Class[] interfaces,
                                       InvocationHandler h)

 3.实现动态代理的步骤

2、(3分)请为第1题中Person类创建代理类 PersonProxy,PersonProxy的在代理Person类的所有setter方法时,把方法的调用时间、方法名称写入到文本文件中,每一行日志的格式为:

* 时间:2012-09-01 23:34:24;方法名称:setName;参数:张小平

3、(3分)请用动态代理技术完成第2题

 

1)创建接口,定义目标类要完成的功能

package homework2.experiment3;

import java.io.IOException;

public interface Speakable {
    public void speak(String message);

    public void setName(String args0) throws IOException;

    public void setTel(String args0) throws IOException;

    public void setGender(String args0) throws IOException;

    public void setId(String args0) throws IOException;
}

2)创建目标类实现接口

package homework2.experiment3;

public class Person implements Speakable {
    private String name;
    private String Gender;
    private String id;
    private String tel;

    public Person() {
    }

    public Person(String args0, String args1, String args2, String args3) {
    }

    public String toString() {
        return null;
    }

    public String getName() {
        return null;
    }

    public void setName(String args0) {
    }

    public String getId() {
        return null;
    }

    public void setGender(String args0) {
    }

    public String getTel() {
        return null;
    }

    public void speak(String args0) {
    }

    public void setTel(String args0) {
    }

    public String getGender() {
        return null;
    }

    public void setId(String args0) {
    }

}

3)创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能:调用目标方法和增强功能

package homework2.experiment3;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Calendar;

public class MyProxy implements InvocationHandler {
    File file = new File("E:\\学习\\代码\\AdvancedJAVA\\src\\homework2\\experiment3\\Log");
    private Object proxied;

    public MyProxy(Object proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy:代理类代理的真实代理对象
        //method:我们要调用某个对象真实的方法的Method对象
        //args:代理对象方法传递的参数
        WriteToText(file, method.getName(), (String) args[0]);
        method.invoke(this.proxied, args);
        return null;
    }

    public void WriteToText(File file, String MethodName, String parameter) throws IOException {

        //如果文件不存在,就动态创建文件
        if (!file.exists()) {
            file.createNewFile();
        }
        FileWriter fw = null;
        String writeDate = "时间:" + this.get_nowDate() + ";" + "方法名称:" + MethodName + ";参数:" + parameter;
        try {
            //设置为:True,表示写入的时候追加数据
            fw = new FileWriter(file, true);
            //回车并换行
            fw.write(writeDate + "\r\n");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fw != null) {
                fw.close();
            }
        }

    }

    private String get_nowDate() {
        Calendar D = Calendar.getInstance();
        int year = 0;
        int moth = 0;
        int day = 0;
        int hour = 0;
        int minute = 0;
        int second = 0;
        year = D.get(Calendar.YEAR);
        moth = D.get(Calendar.MONTH) + 1;
        day = D.get(Calendar.DAY_OF_MONTH);
        hour = D.get(Calendar.HOUR_OF_DAY);
        minute = D.get(Calendar.MINUTE);
        second = D.get(Calendar.SECOND);
        String now_date = String.valueOf(year) + "-" + String.valueOf(moth)
                + "-" + String.valueOf(day) + " " + String.valueOf(hour) + ":"
                + String.valueOf(minute) + ":" + String.valueOf(second);
        return now_date;

    }
}

4)使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。

package homework2.experiment3;

import homework2.experiment1.Speakable;

import java.io.IOException;
import java.lang.reflect.Proxy;

public class BootStrap {
    public static void main(final String[] args) throws IOException {
        //创建一个真实对象
        Person person = new Person();
        //创建一个动态代理对象
        MyProxy myProxy = new MyProxy(person);
        //获取被代理类的CLassLoader对象
        ClassLoader loader = person.getClass().getClassLoader();
        //动态构造一个代理对象
        Speakable speakable = (Speakable) Proxy.newProxyInstance(loader,
                new Class[]{Speakable.class},//接口对象数组,表示我们要给代理对象提供一个怎样的接口,如果提供了这样一组接口数组,就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
                myProxy);
        speakable.setGender("man");


    }
}

 

 

你可能感兴趣的:(java,java学习笔记,java,代理模式,开发语言)