动态代理类实现方式

第一种: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.调用放大器方法创建代理类对象并作为返回值

该方法不需要定义接口,获取的时候声明为目标类就行了,实例化的代理对象是继承目标类的。