java的设计模式中有一项设计模式叫做代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。代理又分为静态代理和动态代理,静态代理就是针对每个被代理对象写一个代理类,操作不够优雅;动态代理,可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮你完成了。
动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类。换句话说,动态代理是一种创建java对象的能力,让你不用创建代理类(jdk内部创建),就能创建代理类对象。
1. jdk动态代理 :使用java反射包中的类和接口实现动态代理的功能。
反射包java.lang.reflect中有三个类:InvocationHandler、 Method、Prooxy。
2. cglib动态代理(了解):第三方工具库,原理是继承目标类,创建它的子类,在子类中重写父类方法,实现功能的修改。所以要求目标类和方法不能是final
cglib要求目标类比较宽松,只要能继承就可。cglib在很多的框架中使用。
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 extends HelloService> 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();
}
}
}
反射包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;
如何使用?
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)
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");
}
}