1 背景回顾
设计模式是一种思维方式,前人总结的最佳实践,也是一种态度,一种进步。
软件过程里面设计模式一共有23种,一般分为3类。即创建型,结构性型,行为型。其中:
创建型5种: 解决了创建对象的烦恼
单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式
结构性型7种: 解决了如何让类组合起来完成复杂的功能
适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式,
行为型11种: 解决了类之间的控制关系。
模版方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,状态模式,策略模式,职责链模式,访问者模式,解释器模式。
如果想要学习并掌握这些设计模式,最好是编码和画图理解。
在学习动态代理之前,最好先学习静态代理,可以看笔者另外一篇基础文章:设计模式之静态代理
2 动态代理
因为静态代理对每个要被代理的类,都要创建一个对应的类,比较麻烦。由此,提出了动态代理,即一个代理可以代理多个真实的类。
需要用到3个类,InvokerHanlder接口,Proxy,前者要使用invoke方法,后者完成生成对应真实类的代理。
2.1 要代理的接口
租房
package demo03;
public interface Rent {
void rent();
}
2.2 真实的角色:房东
package demo03;
public class Host implements Rent {
public void rent() {
System.out.println("房东要租房");
}
}
2.3实现InokerHanlder接口
第一步: 定义被代理的接口
第二步:生成得到代理,通过Proxy.newProxyInstance(ClassLoader,Interfaces,InvokerHanlder),参数分别分类加载器,接口对象,InvokerHanlder
第三步:处理代理实例,并返回结果
package demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理 调用处理器
public class ProxyInvocationHandler implements InvocationHandler {
// 1 定义被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//2 生成得到代理
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//3 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(rent, args);//类似于,rent.method(args)
return result;
}
}
2.4 客户端找代理
package demo03;
public class Client {
public static void main(String[] args) {
//需要先生成一个真实代理的类
Rent host = new Host();
//代理角色, 现在没有
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//通过调用处理角色来处理我们要调用的接口对象
proxyInvocationHandler.setRent(host);
// 动态生成代理
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
执行结果:
3 动态代理进阶
对与第3个角色生成,可以写成一个通用工具类,以后使用时直接用就好了,即达到可以代理很多对象的初衷。
即把Rent接口变为Object就可以了。这个工具类可以代理很多类型对象。
package demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理 调用处理器
public class ProxyInvocationHandler implements InvocationHandler {
// 1 定义被代理的接口
private Object target;
public void setRent(Object target) {
this.target = target;
}
//2 生成得到代理
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//3 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法执行前
Object result = method.invoke(target, args);//类似于,rent.method(args)
// 方法执行后
return result;
}
}
同时,在方法执行前后还能加一些方法:
// 方法执行前
Object result = method.invoke(target, args);//类似于,rent.method(args)
// 方法执行后
具体如下:
package demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理 调用处理器
public class ProxyInvocationHandler implements InvocationHandler {
// 1 定义被代理的接口
private Object target;
public void setRent(Object target) {
this.target = target;
}
//2 生成得到代理
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//3 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);//类似于,rent.method(args)
after();
return result;
}
public void before(){
System.out.println("==========invoke方法执行前======");
}
public void after(){
System.out.println("=====invoke方法执行后=====");
}
}
执行结果:
接口里面如果有多个方法,在使用proxy.xxx()执行前后都会打印出来,这就是AOP的底层。