一. 静态代理
以老板和秘书之间的代理关系,处理事务,秘书作为老板的代理人,可以接电话。
1.首先写一个Handle接口,接口里有一个方法:接电话
public interface Handle {
public void answerPhone();
}
2.分别创建两个类:老板类和秘书类,都实现了Handle接口
2.1老板类重写了接电话的方法
public class Boss implements Handle {
@Override
public void answerPhone() {
// TODO Auto-generated method stub
System.out.println("老板接电话");
}
}
2.2秘书类里一个成员变量Handle,一个构造函数,一个接电话函数
接电话函数里实际上是被代理人在接电话
public class Secretary implements Handle {
private Handle handle;
//这个秘书可以代理任何一人,只要是这个类型
public Secretary(Handle handle){
this.handle = handle;
}
@Override
public void answerPhone() {
// TODO Auto-generated method stub
this.handle.answerPhone();
}
}
3.客户端主函数,实现这个代理过程
/*main
* 电话来了,把秘书叫来
*/
Boss boss = new Boss();
Secretary secretary = new Secretary(boss);//让秘书做老板的代理人
secretary.answerPhone();//秘书去接电话,而实际上是老板接电话
秘书也可以代理其他人,比如总经理等等。
C++代码如下所示:
class Handle{
public:
virtual void AnswerPhone() = 0;
};
class Boss:public Handle{
public:
void AnswerPhone(){printf("老板接电话\n");}
};
class Secretary:public Handle{
public:
Secretary(Handle* handle)
{
this->handle_ = handle;
}
void AnswerPhone()
{
this->handle_->AnswerPhone();
}
private:
Handle* handle_;
};
主函数调用:
Handle* boss = new Boss();
Handle* secretary = new Secretary(boss);
secretary->AnswerPhone();
二. 动态代理
众所周知,sring框架的AOP就采用了动态代理。
1.什么是动态代理?
答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象。
代理一般会实现它所表示的实际对象的接口。
代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。
客户不 知道它是与代理打交道还是与实际对象打交道。
2.为什么使用动态代理?
答:动态代理具有更强的灵活性,以对请求进行任何处理。
它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。
动态代理模式可以使得我们在不改变原来已有的代码结构的情况下,对原来的“真实方法”进行扩展、增强其功能(before和after)。
3.哪些地方需要动态代理?
答:不允许直接访问某些类;
对访问要做特殊处理,代码切入等;
需要对真实对象中的方法进行统一的处理时,比如需要统计每个方法的执行时间,打印出每个方法的执行日志等。
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。
1. 首先写一个Handle接口
public interface Handle {
public void answerPhone();
}
2. 被代理类
//老板类,即被代理类
public class Boss implements Handle {
public void answerPhone() {
System.out.println("老板接电话");
}
}
3. 动态代理类,实现InvocationHandler接口
//动态代理类,实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
// 被代理类的实例,即老板
Object obj = null;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object obj) {
this.obj = obj;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
*
* 动态代理模式可以使得我们在不改变原来已有的代码结构 的情况下,
* 对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
/*
* before :doSomething();
*/
System.out.println("before method invoke");
Object result = arg1.invoke(this.obj, arg2);
/*
* after : doSomething();
*/
System.out.println("after method invoke");
return result;
}
}
4.主函数
public static void main(String[] args) {
//"被代理类"的实例 ,即老板
Handle boss = new Boss();
// 获得“被代理类”的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface
ClassLoader loader = boss.getClass().getClassLoader();
// 获得“被代理类”已实现的所有接口interface,使得动态代理类的实例
Class<?>[] interfaces = boss.getClass().getInterfaces();
//用“被代理类”的实例创建“动态代理类”的实例,用于真正调用处理程序
InvocationHandler handler = new DynamicProxy(boss);
/*
* loader : 被代理类的类加载器
* interfaces :被代理类已实现的所有接口,而这些是动态代理类要实现的接口列表
* handler : 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序
*
* return :返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型
*/
//获得代理的实例
Handle proxy = (Handle) Proxy.newProxyInstance(loader, interfaces, handler);
proxy.answerPhone();
}
运行结果:
before method invoke
老板接电话
after method invoke