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

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

        首先接触动态代理是在学习Struts框架仍是Spring框架这个我已经记不清了。但在学习Spring框架的时候知道其AOP(面向切面编程)技术是依赖动态代理实现的。大体方式了解,但具体细节就不明白了。最近在看MyBatis源码,一开始就遇到了一个地方使用到了Java的动态代理机制。因此借此机会,对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同时仍是全部经过这些静态方法建立出来的代理类的父类。)ide

文档中还提供了如何使用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:调用处理器。即在调用代理类的接口方法时,会关联到咱们指定的调用处理器。我                                       们在调用处理器中就能够在方法执行先后执行咱们要求的任务。spa

总的来讲,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类的方式就不行了,须要使用其余办法。

相关文章
相关标签/搜索