取得该Class对象的类装载器。ClassLoader负责载入系统的所有Resources,通过ClassLoader从而将资源载入JVM,每个class都有一个引用,指向自己的ClassLoader。
第一种方法
Car car = new Car();
Class carClass = car.getClass();
InvocationHandler timeHandler = new TimeHandler(car);
Moveable proxy = (Moveable) Proxy.newProxyInstance(carClass.getClassLoader(),
carClass.getInterfaces(),timeHandler);
InvocationHandler logHandler = new LogHandler(proxy);
Moveable proxy2 = (Moveable) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
proxy.getClass().getInterfaces(), logHandler);
proxy2.move();
第二种方法
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);
InvocationHandler h2=new LogHandler(m);
Class<?> clh=m.getClass();
Moveable m2=(Moveable)Proxy.newProxyInstance(clh.getClassLoader(),
clh.getInterfaces(), h2);
m2.move();
其实都差不多。。。
构造器就是构造方法,还有人叫构造函数,至于为什么不统一呢,只能翻译背锅吧。
method.invoke(target)=====target.method
public static void main(String[] args) { Car car=new Car(); InvocationHandler h=new TimeHandler(car); Class<?> cls=car.getClass(); /* * #参数 * loader 类加载你 * interfaces 实现接口 * h InvovationHandler * * 用newProxyInstance()动态创建一个代理类 */ Moveable m=(Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); InvocationHandler h2=new LogHandler(m); Class<?> clh=m.getClass(); Moveable m2=(Moveable)Proxy.newProxyInstance(clh.getClassLoader(), clh.getInterfaces(), h2); m2.move(); }
同问,我也是这里没看懂
TimeHandler的构造方法写了吗
InvocationHandler invocationHandler2=new LogHandler(moveable);
Class<?> class2 = moveable.getClass();
Moveable moveable2 =(Moveable)Proxy.newProxyInstance(class2.getClassLoader(), class2.getInterfaces(), invocationHandler2);
moveable2.move();
JDK 动态代理作业可以参考这个
https://github.com/imooc-java/proxy/blob/master/src/test/java/com/imooc/jdkproxy/HandlerTest.java
代理的代理,就是将用时间增强过的代理再用日志增强,这样就可以同时输出时间和日志,应该对car的时间增强代理类增强日志功能。看不懂你的ctp和clp的意义何在,你可能将动态代理和静态代理混淆了,你这里的代理处理器还是对时间的增强,并没有对日志增强的代理处理器。(动态代理是依据代理处理器来动态创建代理的。)
最后一个参数是必须实现了InvactionHandler接口的对象,通过newProxyInstance函数返回proxy的实例是调用实现了InvactionHandler接口对象重写的invoke方法,而此方法中里面的参数对象是被代理类的实现了某个接口的具体方法,通俗一点就是中介的角色,具体干实事是被代理类实现某接口的具体方法,当然在invoke方法中可以加入一些业务逻辑代码,也是就是spring框架里面的aop通知实现的原理
//创建代理对象,因为代理代理对象实现的都是同一个接口所以产生的代理对象是实现的接口,变现了多态的作用
Proxy.newProxyInstance(加载器,实现的接口,处理器);
加载器:就是类加载器
实现接口:就是car中继承的接口
处理器:就是我们写的那个处理器,TimeHanlder
聚合代理也能完成,聚合方式产生的代理比继承方式更好!所以聚合代理一样可以用同样的日志代理和时间代理类的,具体的可以搜索相关视频哦
因为你这两个handler里的invoke方法里的method.invoke语句最后都是调的move()方法啊。
你timehandler传的对象是car,之后的loghandler传的timecar,所以你最后logcar调用move()方法的时候的执行顺序是
执行loghandler的invoke方法中method.invoke语句前的部分
进入loghandler的method.invoke方法,这里实际是timehandler的invoke方法,同样先执行method.invoke语句之前的部分
执行timehandler的method.invoke方法,这里实际是car的move()方法
执行timehandler的invoke方法里method.invoke语句之后的部分
执行loghandler的invoke方法里method.invoke语句之后的部分
解释:
1. Proxy即动态代理类;
2. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用;
它有三个参数:
ClassLoader loader ----指定被代理对象的类加载器
Class[] Interfaces ----指定被代理对象所以事项的接口
InvocationHandler h ----指定需要调用的InvocationHandler对象
3. 实现InVocationHandler接口的LogHandler_old对象
这个对象的invoke()方法就是Proxy这个动态代理类所代理的接口类的抽象方法的真实实现;
它有三个参数:
Object proxy -----代理类对象
Method method -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args -----该方法的参数数组
JDK中具体的动态代理类是怎么产生的呢?
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2. 将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中
3. 创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象
参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数
这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;
4. 生成代理类的class byte
动态代理生成的都是二进制class字节码
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
动态代理是很多框架和技术的基础, spring
的AOP实现就是基于动态代理实现的。了解动态代理的机制对于理解AOP的底层实现是很有帮助的。
Proxy类的设计用到代理模式的设计思想,Proxy类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种替代不是一种简单的替代,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所以,Proxy应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口。
InvocationHandler接口也是在java.lang.reflec
Object invoke(Object proxy, Method method, Object[] args)
这个接口有三个参数,其中第二和第三个参数都比较好理解,一个是被拦截的方法,一个是该方法的参数列表。关键是第一个参数。按照doc文档的解析,
proxy - the proxy instance that the method was invoked on
也就是说,proxy应该是一个代理实例,但为什么要传入这个参数呢?
带着这个问题,自己编了个小程序作了一点试验。
///////////////////////////////////////
public interface IAnimal {
void info();
嗯…………………………
接上面回答,调用时候得到日志记录的对象后, 再通过LogHandler代理一次即可:代码如下:
public static void main(String[] args) { Moveable car = new Car(); InvocationHandler timeHandler = new TimeHandler(car); Class<?> cls = car.getClass(); /** * loader:类加载器<br> * interfaces:实现接口<br> * h InvocationHandler<br> */ Moveable timeCar = (Moveable) Proxy.newProxyInstance( cls.getClassLoader(), cls.getInterfaces(), timeHandler); InvocationHandler logHandler = new LogHandler(timeCar); Moveable logCar = (Moveable) Proxy.newProxyInstance( cls.getClassLoader(), cls.getInterfaces(), logHandler); logCar.move(); }