动态代理
一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。
package com.ddyblackhat.javase.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Subject {// 抽象类
public void doSomething();
}
interface Say {
public void saySomething();
}
class RealSubject implements Subject, Say {// 实现类
@Override
public void doSomething() {
System.out.println("call doSomething()");
}
@Override
public void saySomething() {
// TODO Auto-generated method stub
System.out.println("say something");
}
}
// class SubjectProxy implements Subject{// 静态代理
//
// Subject subimpl = new RealSubject();
// @Override
// public void doSomething() {
// subimpl.doSomething();
// }
// @Override
// public void saySomething() {
// // TODO Auto-generated method stub
//
// }
//
// }
class ProxyHandler { // 动态代理
private Object tar; // 要代理的对象
public ProxyHandler(Object tar) {
this.tar = tar;
}
public Object getProxy() {
if (tar == null)
throw new RuntimeException("tar is null");
// 1. 准备目标对象的类加载器
// ①获取目标对象的Class类对象
Class<? extends Object> tarClass = this.tar.getClass();
// ②获取类加载器对象
ClassLoader loader = tarClass.getClassLoader();
// 2. 准备目标对象所实现的接口类型的数组
Class<?>[] interfaces = tarClass.getInterfaces();
// 3. 准备InvocationHandler对象
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
String className = tar.getClass().getName();
String methodName = method.getName();
Object result = null;
try {
System.out.println("[日志][" + className + "]" + methodName + "开始...");
result = method.invoke(tar, args);
System.out.println("[日志][" + className + "]" + methodName + "正常结束...");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("[日志][" + className + "]" + methodName + "异常结束...");
e.printStackTrace();
} finally {
System.out.println("[日志][" + className + "]" + methodName + "最终结束...");
}
return result;
}
};
Object o = Proxy.newProxyInstance(loader, interfaces, h);
return o;
}
}
public class ProxyTest {
public static void main(String[] args) {
// Subject sub = new SubjectProxy();
// sub.doSomething();
ProxyHandler proxy = new ProxyHandler(new RealSubject());
Subject rs = (Subject) proxy.getProxy();
Say say = (Say) proxy.getProxy();
rs.doSomething();
say.saySomething();
}
}
输出:
[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething开始...
call doSomething()
[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething正常结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething最终结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething开始...
say something
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething正常结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething最终结束...
使用java自带的动态代理实现,
- 实现InvocationHandler 接口创建自己的调用处理器。
- 通过Proxy.newProxyInstance创建代理类。需要传入3个参数。
- classloader
- interfaces
- invocationHandler 对象。
代理角色
- 抽象角色:声明真实对象和代理对象的共同接口,这样一来在任何使用目标对象的地方都可以使用代理对象。
- 代理角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调动传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象的封装。
- 真实角色:著作权归作者所有。定义了代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象,定义了代理对象所代表的目标对象。
动态代理的作用
- Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大
- 可以实现AOP编程,实际上静态代理也可以实现,AOP可以算作是代理模式的一个典型应用
- 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。
拓展
- 可以使用Properties属性文件配置要代理的类。
- 目标方法的前后动态的插入方法,而不是单一功能。(这个可以怎么实现?)