在讲正题之前,先了解一下代理模式,非常形象逼真的买房子实例又要来了。
A去买房子,让B房屋中介公司负责相关事宜,比如看房子结构地段和卖房公司商量价格等等(没买过房子 乱讲的)
那么此时具体去买房子所要做的事情本来该是A做的,因为他要买房啊,但是却交给了B来管,
此时,A是被代理对象,B为代理对象
代理模式可以分为:远程代理,虚拟代理,保护代理,智能引用代理
代理模式的实现方法为;静态代理和动态代理
其中静态代理又分为 继承代理和聚合代理,在这就不敞开叙述了,一般情况下,采用聚合代理居多
使用JDK和CGLIB的区别
JDK只能代理实现了接口的类,如果没有实现接口的类则不能实现jdk动态代理
CGLIB是针对类来实现代理,对指定目标类产生一个子类,通过方法来拦截技术拦截所有父类方法的调用
也就是说,CGLIB不能代理用final修饰的类
下面讲 如何使用JDK代理实现动态代理
实现步骤:
1. 创建一个实现接口InvocationHandler的类,必须实现invoke方法,在invoke方法中放我们的业务逻辑处理
2.创建被代理的类以及接口(类必须实现接口)
3.在mian中调用Proxy静态方法,创建一个代理类
具体的实现过程:通过newProxyInstance返回代理对象
(1)声明一段源码,动态的产生代理
(2)编译源码(JDK Compiler API),产生新的类,也就是代理类
(3)将这个类load到内存当中,产生一个新的对象,也就是代理对象
(4)return 代理对象
4.通过代理调用方法
代码示例:
接口:
public interface Moveable {
void move();
}
实现类:
public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
事务处理类:
public class TimeHandler implements InvocationHandler {
public TimeHandler(Object target) {
super();
this.target = target;
}
private Object target;
/*
* 参数:
* proxy 代理对象
* method 被代理对象的方法
* args 方法的参数
*
* 返回值:
* Object 方法的返回值
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶....");
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶.... 汽车行驶时间:" + (endtime - starttime) + "毫秒!");
return null;
}
}
测试类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.imooc.proxy.Car;
import com.imooc.proxy.Moveable;
public class Test {
/**
* JDK动态代理测试类
*/
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class> cls = car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
m.move();
}
}
此时如果想在时间处理事务的基础上添加其他处理,比如日志记录,则可再写一个实现了InvocationHandler接口的
LogHandler类,注意在Main方法中,添加loghandler时,可以选择先输出log还是时间
注意是哪个放在后面,就先执行哪个
public class Test {
public static void main(String[] args) {
/**
* 先Log后Time
*/
Car c=new Car();
InvocationHandler h=new TimeHandler(c);
Class> cla=c.getClass();
Moveable m=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), h);
InvocationHandler h2=new LogHandler(m);
Moveable m2=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), h2);
m2.move();
/**
* 先Time后Log
*/
Car c=new Car();
InvocationHandler h=new LogHandler(c);
Class> cla=c.getClass();
Moveable m=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), h);
InvocationHandler h2=new TimeHandler(m);
Moveable m2=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), h2);
m2.move();
}
}
Log先的输出:
log start!
start
end 10008
log end!
CGLIB实现动态代理
被代理类:
public class Car {
public void move(){
System.out.println("moving...");
}
}
事务处理:
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* obj 目标类的实例
* m 目标方法的反射对象
* args 方法的参数
* proxy代理类的实例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("日志开始...");
//代理类调用父类的方法
proxy.invokeSuper(obj, args);
System.out.println("日志结束...");
return null;
}
}
测试类:
public class Test {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Car t = (Car)proxy.getProxy(Car.class);
t.move();
}
}
输出:
日志开始...
moving...
日志结束...