1. 动态代理概念:
- 代理对象存在的价值: 主要用于拦截对真实业务对象的访问。
- 代理对象有什么方法: 一般来说,真实业务对象具有什么方法,那么代理对象就会具备相应的方法。
2. 设计要素
- 代理谁?
须设计一个类变量,以及一个构造函数,记住代理类代理哪个对象。 - 如何生成代理对象?
设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)
3. Proxy类
Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
- 生成代理对象使用哪个类装载器。
- 生成哪个对象的代理对象,通过接口指定。
- 生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
4. 注意
- Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
- 由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
5. 约定:要想创建某一个对象的代理对象,那么该对象必须实现一个接口。
6. 简单示例
1). 创建接口Person
public interface Person {
/**
* 唱歌
*/
void sing();
/**
* 跳舞
*/
void dance();
}
2). 创建实现Person接口的PersonImpl类
public class PersonImpl implements Person{
@Override
public void sing() {
System.out.println("开始唱歌");
}
@Override
public void dance() {
System.out.println("开始跳舞");
}
}
3). 创建代理类
public class PersonImplProxy {
private Person person = new PersonImpl();
/**
* 创建代理
* @return 返回值是接口类型
*/
public Person createProxy() {
/**
* 产生某个对象的代理对象
* ClassLoader loader 当前代理对象的类加载器
* Class<?>[] interfaces 代理对象的接口
* InvocationHandler h InvocationHandler对象
*/
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
/**
* @param proxy 把代理对象自身传进去
* @param method 代表当前调用的方法
* @param args 当前调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 编写代码
return null;
}
});
}
}
4). 编写Demo类中主函数main()
public class Demo {
public static void main(String[] args) {
PersonImplProxy proxy = new PersonImplProxy();
Person person = proxy.createProxy();
person.sing();
person.dance();
}
}
5). 实现代理对象中的createProxy方法中的invoke方法
public class PersonImplProxy {
private Person person = new PersonImpl();
/**
* 创建代理
* @return 返回值是接口类型
*/
public Person createProxy() {
/**
* 产生某个对象的代理对象
* ClassLoader loader 当前代理对象的类加载器
* Class<?>[] interfaces 代理对象的接口
* InvocationHandler h InvocationHandler对象
*/
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
/**
* @param proxy 把代理对象自身传进去
* @param method 代表当前调用的方法
* @param args 当前调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 编写代码
// 获取方法名
String methodName = method.getName();
if ("sing".equals(methodName)) {
System.out.println("啦啦啦啦啦啦啦啦");
method.invoke(person, args);
} else if ("dance".equals(methodName)) {
System.out.println("哈哈哈哈哈哈哈哈");
method.invoke(person, args);
} else {
System.out.println("啊啊啊啊啊啊啊啊");
}
return null;
}
});
}
}
6). 调用main方法,打印结果:
7. 高级进阶--接口方法中带参数带返回值
1). 创建Person接口
public interface Person {
/**
* 唱歌
* @param name 歌曲名
* @return
*/
String sing(String name);
/**
* 跳舞
* @param name 舞曲名
* @return
*/
String dance(String name);
}
2). 创建实现Person接口的PersonImpl类
public class PersonImpl implements Person {
@Override
public String sing(String name) {
System.out.println("唱" + name);
return "唱完了";
}
@Override
public String dance(String name) {
System.out.println("跳" + name);
return "不好玩";
}
}
3). 创建PersonImpl的代理类
public class PersonImplProxy {
private Person person = new PersonImpl();
public Person createProxy() {
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 编写代码
return null;
}
});
}
}
4). 编写Demo类中主函数
public class Demo {
public static void main(String[] args) {
PersonImplProxy proxy = new PersonImplProxy();
Person person = proxy.createProxy();
System.out.println(person.sing("说散就散"));
System.out.println(person.dance("体面"));
}
}
5). 实现代理对象中的invoke方法
public class PersonImplProxy {
private Person person = new PersonImpl();
public Person createProxy() {
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 编写代码
String methodName = method.getName();
if ("sing".equals(methodName)) {
System.out.println("啦啦啦啦啦啦");
return method.invoke(person, args);
} else if ("dance".equals(methodName)) {
System.out.println("哈哈哈哈哈哈");
return method.invoke(person, args);
} else {
System.out.println("哈哈哈哈哈哈");
}
return null;
}
});
}
}
6). 执行主函数, 打印结果