java的动态代理机制详解--20
@设计模式——代理模式——静态代理的实现
1、聚合代理优于继承代理。因为实现功能叠加的情况下,聚合代理通过相互代理可以实现功能重用,而继承代理必须写多个类来实现多功能叠加。 2、但静态代理只能代理一种类型的被代理类,换个类型的就不行了,这需要动态代理 静态代理的两种实现方式对比(继承方式和聚合方式)案例--代理类功能的叠加
1. 继承的方式:
如果使用继承的方式来实现我们代理功能的叠加, 我们的代理类会无限的膨胀下去。2. 聚合的方式:
由于代理类和被代理类都实现了相同的接口,那么代理类的构造参数就可以传入该 相同的接口,这样在后面功能叠加的时候就可以传入其他功能的代理类,因为他们 都实现了相同的父接口。从而达到功能叠加的作用。public interface Moveable { void move(); }
public class CarTimeProxy implements Moveable { public CarTimeProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶...."); m.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶.... 汽车行驶时间:" + (endtime - starttime) + "毫秒!"); } }
public class Car implements Moveable { @Override public void move() { //实现开车 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
聚合的方式比继承的方式灵活很多,通过聚合的方式,代理之间也是可以相互传递的,相互组合。eg:汽车类,先记录日志再记录时间 Car car = new Car(); CarTimeProxy ctp = new CarTimeProxy(car); CarLogProxy clp = new CarLogProxy(ctp); clp.move(); 先记录时间再记录日志 Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move();
JDK动态代理
1. 目的:动态产生代理,实现对【不同类】,【不同方法】的代理
2. java动态代理类,位于java.lang.reflect包下,一般涉及两个类:(1)Interface InvocationHandler:
该接口中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args):实际使用中,
obj指被代理类的对象,
method指被代理的方法,
args为该方法参数数组。
这个抽象方法在代理类中动态实现。实现该接口即为代理的事务处理器。![]()
(2)Proxy:该类即为动态代理类:
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以被当作代理类使用(可使用被代理类的在【接口中】声明过的方法)。
第一个参数loader为被代理类的加载器,通过被代理类.getClass().getClassLoader()得到 · 第二个参数interfaces为被代理类实现的所有接口,同样通过getClass().getInterfaces()得到 · 第三个参数handler就是自己实现的InvocationHandler的实现类的对象
![]()
3. 动态代理实现:
1) 声明一个代理h实现InvocationHandler接口,通过【构造方法接受被代理类】,并实现invoke方法,添加业务逻辑(实现原有功能并添加额外功能) 2) 在测试类中,通过共同实现接口的实例获得代理对象,并实现方法,如Interface1 i = (Interface1)Proxy.newProxyInstance(classLoader,classInterfaces,h); 3) 通过动态代理对象m,代用其方法i.fun();

相关代码——(上):
@Car.java
public class Car implements Moveable{
public void move() {
//实现打车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("车行驶中...");
} catch (Exception e) {
e.printStackTrace();
}
}
public void move1() {
// TODO Auto-generated method stub
System.out.println("move1");
}
}
@TimeHandler.java
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* 参数:
* proxy:被代理对象;method:被代理对象的方法;args:方法的参数。
* 返回值:
* Object:方法的返回值。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long starttime=System.currentTimeMillis();
System.out.println("车开始行驶...");
method.invoke(target);//通过反射机制:Method是一个方法,方法对象。Method.Invoke()相当于method();
long endtime=System.currentTimeMillis();
System.out.println("车结束行驶。");
System.out.println("车行驶时间:"+(endtime-starttime)+"毫秒!");
return null;
}
}
相关代码——(下):
@TestJDKProxy.java
public class TestJDKProxy {
/**
* JDK动态代理测试类
*/
public static void main(String[] args) {
Car car=new Car();
InvocationHandler h=new TimeHandler(car);
Class<?> cls=car.getClass();
/**
* 参数:loader:类加载器;interface:实现接口;h:InvocationHandler。
*/
Moveable m=(Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
m.move();
m.move1();
/**
* 执行顺序:m.move()后先执行TimeHandler类中的invoke()方法,
* 当执行到method.invoke(target);时,再去执行目标类Car的move()方法,
* 然后返回method.invoke(target);的下一句,最后返回这里执行完毕。
*/
}
}
@Moveable.java
public interface Moveable {
void move();
void move1();
}
一、JDK与CGLIB动态代理的区别
1、JDK:针对接口
· 只能代理【实现了接口的类】 · 没有实现接口的类不能实现JDK的动态代理2、CGLIB:针对类
· 针对类来实现代理的 · 对指定目标类产生一个子类,通过方法拦截【技术拦截】所有父类方法的调用
· 注意:CGLIB不能对“final”修饰的类进行代理。
二、CGLIB:是一个强大的开源项目,可以在运行期扩展Java类与实现Java接口。
相关代码——(上): @Client.java public class Client { public static void main(String[] args) { //创建代理类返回对象 CglibProxy proxy=new CglibProxy(); //得到代理类的对象 Train t=(Train) proxy.getProxy(Train.class); t.move(); /** * 执行顺序(类似JDK动态代理):从proxy.getProxy(Train.class);后,开始先执行CglibProxy类的getProxy()方法, * 再返回到t.move();后,接着执行CglibProxy类的intercept()方法,等到methodproxy.invokeSuper();则执行Train类中的move()方法, * 然后返回到methodproxy.invokeSuper();下一句直到最后,再接着返回到Client类,完毕。 */ } }
@Train.java public class Train { public void move(){ System.out.println("火车行驶中..."); } }
相关代码——(下):
@CglibProxy.java
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer=new Enhancer();
// 得到代理类
public Object getProxy(Class cls){
//设置创建子类的类
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
//返回子类的实例
return enhancer.create();
}
/**
* 参数:object:拦截所有目标类方法的调用,
* method:目标方法的反射对象,
* args:方法的参数,
* methodproxy:代理类的实例。
*/
public Object intercept(Object object, Method method, Object[] args,
MethodProxy methodproxy) throws Throwable {
syso("日志开始...");
//代理类调用父类的方法
methodproxy.invokeSuper(object, args);
syso("日志结束...");
return null;
}
}