前面文章有说到代理模式:http://aphysia.cn/archives/dynamicagentdesignpattern
那么回顾一下,代理模式怎么来的?假设有个需求:
在系统中所有的
controller
类调用方法之前以及之后,打印一下日志。
假设原来的代码:
public class Person{
public void method(){
// 表示自己的业务逻辑
process();
}
}
如果在所有的类里面都添加打印方法,这样肯定是不现实的,如果我有几百个这样的类,写到崩溃,况且重复代码太多,冗余,还耦合到一块了,要是我下次不打日志了,做其他的,那几百个类又全部改一遍。
public class Person{
public void method(){
log();
// 表示自己的业务逻辑
process();
log();
}
}
静态代理
怎么样写比较优美呢?静态代理 这时候出场了,先把方法抽象成为接口:
public class IProxy(){
public void method();
}
让具体的类去实现 IProxy
,写自己的业务逻辑,比如:
public class Person implements IProxy(){
public void method(){
// 表示自己的业务逻辑
process();
}
}
然后弄个代理类,对方法进行增强:
public class PersonProxy implements IProxy{
private IProxy target;
public PersonProxy(IProxy target){
this.target = target;
}
@Override
public void method() {
log();
target.method();
log();
}
}
调用的时候,把真实的对象放到代理类的构造器里面,就可以得到一个代理类,对它的方法进行增强,好处就是,如果下次我要改,不打日志,做其他事情,我改代理类就可以了,不用到处改我的目标类的方法,而坏处还是很明显,要增强哪一个类,就要为它写一个代理类,这样好像不是很合理。
动态代理
怎么样能让他自动生成代理对象呢? 动态代理做的就是这个事情,它可以 动态 的根据我们提供的类,生成代理类的对象。
最主要的,是在运行时,动态生成,只要传入我们要代理增强的类相关的信息,比如类对象本身,类加载器,类的接口等,就可以生成,不用提前知道它是 A 类,B 类还是 C 类。
动态代理主要有三种实现方法,今天我们重点分析 JDK 动态代理:
- JDK 代理:使用 JDK 提供的官方的 Proxy
- 第三方 CGlib 代理:使用 CGLib 的 Enhancer 类创建代理对象
- javassit:Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。
JDK 动态代理
使用步骤
- 新建一个接口
- 新建一个类,实现该接口
- 创建代理类,实现
java.lang.reflect.InvocationHandler
接口
代码如下:
IPlayDao.java
(玩的接口)
public interface IPlayDao {
void play();
}
StudentDao.java
(实现了买东西,玩的接口的学生类)
public class StudentDao implements IPlayDao {
@Override
public void play() {
System.out.println("我是学生,我想出去玩");
}
}
MyProxy.java 代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy {
private Object target;
public MyProxy(Object target){
this.target=target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
// 一个接口可能很多方法,要是需要针对某一个方法,那么需要在函数里判断 method
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(</