spring框架之动态代理类——附:声明类型与实例类型(不一致问题)
动态代理类实现方式
第一种:jdk实现(面向接口)
第一步:实现InvocationHandler接口
该接口是java反射包里面定义的。获取代理类的原理是通过Proxy类的newProxyInstance方法通过反射机制获取目标类的字节码类加载器,还有接口类型。
第二步:实现接口中的invoke方法。
第三步:获取一个代理类getproxy
该方法是需要定义接口的,获取的时候也是要通过声明接口类型,实例化的代理对象是目标类的兄弟。
附:声明类型与实例类型不一致问题
在测试的时候,我通过实例化1个工厂类,去获取2个不同的目标类的代理类,代码如下:
//使用一个工厂代理类,就能创建多个代理类对象
ServiceProxyFactory factory = new ServiceProxyFactory();
//ServiceProxyFactory factory2 = new ServiceProxyFactory(); 备用工厂
//创建目标类实例(2个)
BookServiceIfac bookservice = new BookServiceImpl();
PlayServiceIfac playService = new PlayServiceImpl();
BookServiceIfac proxy1 = (BookServiceIfac) factory.getProxy(bookservice);
PlayServiceIfac proxy2 = (PlayServiceIfac) factory.getProxy(playService);
proxy1.borrowBook("九阳神功");
proxy2.playGame("tom");
proxy2.playToy("marry");
此时上面的代码看上去应该没什么问题,而且编译器也不会报检查错误,但在运行时,就出现了如下的错误
object is not an instance of declaring class(该对象不是一个声明类的对象)
其实只要改正一下代码的位置就能解决了,代码如下:
//使用一个工厂代理类,就能创建多个代理类对象
ServiceProxyFactory factory = new ServiceProxyFactory();
//ServiceProxyFactory factory2 = new ServiceProxyFactory(); //备用工厂
//创建目标类实例(2个)
BookServiceIfac bookservice = new BookServiceImpl();
PlayServiceIfac playService = new PlayServiceImpl();
BookServiceIfac proxy1 = (BookServiceIfac) factory.getProxy(bookservice);
proxy1.borrowBook("九阳神功");
PlayServiceIfac proxy2 = (PlayServiceIfac) factory.getProxy(playService);
proxy2.playGame("tom");
proxy2.playToy("marry");
总结:
一定要在获取该声明类型的代理类时使用方法,不然使用同一个工厂创建另外的代理类对象时,声明就会改变,此时如果再使用之前的代理类方法,则会报 该实例不是声明的对象类型的错误 。
但是,如果想要避免这错误,就要实例化2个工厂对象(也就是上面代码注释掉的备用工厂),但这样就跟静态代理时创建方式一样了,虽然不用创建多个工厂类。
第二种:cglib实现(面向对象–继承)
第一步:导入 asm cglib 包
(注意版本问题:使用asm-3.2.jar时,cglib的版本一定要3.0以下,如cglib-2.2.jar)
第二步:实现 MethodInterceptor接口
第三步:定义生成代理对象的方法getproxy
其中需要创建一个放大器对象(Enhancer)
1.设置父类对象(即为目标类)
2.设置回调函数(当我们调用代理对象的方法时后台调用的是回调对象的intercept方法)
3.调用放大器方法创建代理类对象并作为返回值
该方法不需要定义接口,获取的时候声明为目标类就行了,实例化的代理对象是继承目标类的。
上一篇: 硬件创业潮来 最高兴的是云平台