Java动态代理(Proxy+Cglib)详解

对本片内容有不明白的地方请提问我,我如果也不懂会再去学习掌握然后再补充完善,谢谢。

        首先接触动态代理是在学习Struts框架还是Spring框架这个我已经记不清了。但在学习Spring框架的时候知道其AOP(面向切面编程)技术是依赖动态代理实现的。大致方式了解,但具体细节就不明白了。最近在看MyBatis源码,一开始就遇到了一个地方使用到了Java的动态代理机制。所以借此机会,对Java的动态代理机制进行探究和分析以及学习,一方面再遇到动态代理的问题时能够明白实现细节,再一个在日后编程时也能够借助动态代理来完成一些特定任务。

        此篇笔记是基于以下博客的内容,加以自己的分析理解来写的。自己写技术文章功力不行,如果看不明白可以参考原博客的内容,或许能更容易明白些。
http://www.cnblogs.com/xiaoluo501395377/p/3383130.html
 

我一般习惯于先了解相关类结构及关系,然后再看内部的方法和实现细节代码。要使用Java动态代理,必须使用接口InvocationHandler和类Proxy
先看下Proxy这个类,如果先看InvocationHandler接口的话不容易明白。Proxy类在JDK1.7的文档描述如下:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.(Proxy类提供了一些静态方法用来创建动态代理的类和它们的实例对象。Proxy同时还是所有通过这些静态方法创建出来的代理类的父类。)

文档中还提供了如何使用Proxy来创建动态代理类:

//To create a proxy for some interface Foo:
    //创建一个InvocationHandler接口的实例
     InvocationHandler handler = new MyInvocationHandler(...);
        //创建代理类的Class信息
     Class proxyClass = Proxy.getProxyClass(
         Foo.class.getClassLoader(), new Class[] { Foo.class });
        //根据Class信息实例化代理类的对象
     Foo f = (Foo) proxyClass.
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });

//or more simply://另一种简易方式
     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class[] { Foo.class },
                                          handler);

        由上面代码可知,Proxy类可以先使用getProxyClass来获取代理类的Class,然后再根据Class信息实例化具体的代理类实例。也可以直接使用Proxy类的newProxyInstance方法来直接获取一个代理类对象。我们直接看newProxyInstance这个方法

public static Object newProxyInstance(
    ClassLoader loader,
    Class<?>[] interfaces,
   InvocationHandler h
)

该方法有三个参数:

ClassLoader loader:类加载器,声明使用哪个加载器来加载生成后的代理类对象。
Class<?>[] interfaces:一组接口的Class信息,声明我们要生成的代理类对象实现了这些接口,既然实现                                     了这些接口,那么就可以调用代理类对象中的这些接口方法。
InvocationHandler h:调用处理器。即在调用代理类的接口方法时,会关联到我们指定的调用处理器。我                                       们在调用处理器中就可以在方法执行前后执行我们要求的任务。

总的来说,ClassLoader决定了用哪个加载器加载生成的代理对象。interfaces决定了代理类能执行哪些方法。invocationHandler决定了在执行调用方法时,我们能在执行前后做什么。

然后我们再看下InvocationHandler这个接口信息,先看下JDK中如何描述:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

代理类实例的调用处理器实现了该接口。每一个代理类实例都关联了一个调用处理器。当代理类调用某个方法时,这个方法调用会被分发到我们关联的调用处理器中进行调用执行(大致意思就是这,英文高手见谅...)。

InvocationHandler接口只有一个invoke方法。也就是说我们实现的调用处理器都要实现invoke方法。

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

下面开始用实例来示范Java动态代理具体怎么使用。

动态代理是基于接口的,所以我们先声明一个接口:

package com.yalonglive.java.proxy;

import java.util.List;

/*
 * Jdbc服务接口,用来执行query,update,delete,insert等方法。
 */
public interface JdbcService {
	
	/**
	 * 查询单个对象
	 * @param id
	 */
	Object queryObject(String id);
	
	/**
	 * 查询对象列表
	 * @param entity
	 */
	List queryList(String entity);

}

然后声明接口的实现类,也就是我们要代理的对象:

package com.yalonglive.java.proxy;

import java.util.ArrayList;
import java.util.List;

public class JdbcServiceImp implements JdbcService {

	@Override
	public Object queryObject(String id) {
		System.out.println("执行queryObject方法");
		return new Object();
	}

	@Override
	public List queryList(String entity) {
		System.out.println("执行queryList方法");
		return new ArrayList<Object>(0);
	}

}

在接口中,我们定义了JdbcService可以执行的两个方法queryObject和queryList。以及对应的实现类,接下来我们开始创建代理对象,我这里按照JDK文档中的方法创建:

/**
	 * 测试代理类:先创建代理类信息
	 * @throws Exception
	 */
	public static void testProxy() throws Exception {
		
		//声明一个要被代理的对象
		final JdbcService jdbcService = new JdbcServiceImp();
		
		//创建调用处理器,将被代理的对象和调用处理器进行关联
		InvocationHandler handle = new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				
				System.out.println("方法调用前执行代码段");
				
				//代理类在调用任何注册过的接口方法时都会通过其调用处理器来执行对应的方法(通过反射),那么在此处就可以定义一些自定义操作了
				method.invoke(jdbcService, args);
				
				System.out.println("方法调用后执行代码段");
				
				return null;
			}
		};
		
		//创建代理类Class信息
		Class proxyClass = Proxy.getProxyClass(JdbcService.class.getClassLoader(),new Class[] {JdbcService.class});
		
		//生成代理类对象
		JdbcService proxyObject = (JdbcService)proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(handle);
		
		//执行代理类的方法
		proxyObject.queryObject("1");
		
		//输出:
		//方法调用前执行代码段
		//执行queryObject方法
		//方法调用后执行代码段
	}

        其实在写上面的Demo之前,我在想代理对象,调用处理器,被代理对象之间的关系是什么,他们是如何进行交互的,为什么执行代理类的方法就会执行被代理类的方法。
        从上面的Demo可以看出。实际上是:代理类<------>调用处理器<------>被代理类。也就是说,创建代理类的时候引用了调用处理器,而在创建调用处理器对象的时候引用了被代理类对象。所以代理类对象就可以调用被代理类的方法了,调用处理器就是中间的“桥梁”,同时也是我们编写自定义逻辑代码的地方。

        到这里就能知道Java动态代理的实现方法了,改如何使用。大家如果有不明白的地方或者想知道的内容可以留言我,我会继续完善,后面会继续补充Proxy这个类内部的一些源码分析。

通过上面的讲解,我们只要能获取到对象的接口信息,就能创建一个该对象的代理类来对其进行代理操作,但是还有的时候我们的操作类并没有实现相关接口,但我们还有代理该对象的需求,此时,使用Proxy类的方式就不行了,需要使用其他办法。

 

转载于:https://my.oschina.net/u/1272088/blog/1526648

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值