java的动态代理机制详解--20

本文深入探讨Java动态代理机制,包括静态代理与动态代理的区别、JDK动态代理与CGLIB的不同之处及其应用场景。通过具体代码示例展示了如何利用JDK动态代理及CGLIB实现方法的拦截与增强。

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;
}
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值