AOP底层-JDK动态代理


需求:CustomerService业务类,有save,update方法,希望在save,update方法执行之前记录日志。

接下来使用JDK动态代理实现:

一、编写业务类

CustomerService接口:

package com.yiidian.service;
/**
 * @author http://www.yiidian.com
 *
 */
public interface CustomerService {

	public void save();
	
	public void update();
}

CustomerServiceImpl实现:

package com.yiidian.service.impl;

import com.yiidian.service.CustomerService;
/**
 * 这个类在AOP属于目标对象(Target)
 * @author http://www.yiidian.com
 *
 */
public class CustomerServiceImpl implements CustomerService {

	@Override
	public void save() {
		System.out.println("执行save方法");
	}

	@Override
	public void update() {
		System.out.println("执行update方法");
	}

}

二、编写JDK动态代理工具类

该工具类,专门用于生成某个接口实现类(目标对象)的代理对象。

package com.yiidian.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author http://www.yiidian.com
 *
 */
public class JDKProxyUtils {

	/**
	 * 使用JDK动态代理获取代理对象
	 * target: 目标对象
	 * @return
	 */
	public static Object getProxy(final Object target){
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(),    // 和目标对象一样的类加载器
				target.getClass().getInterfaces(), // 目标对象的接口列表
				new InvocationHandler() {
					
					//invoke: 这个方法在每次调用代理类对象的时候被执行啦!!!
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						System.out.println("记录日志");
						
						//调用目标对象的方法
						return method.invoke(target, args);
					}
				});
	}
}

三、编写测试类

package com.yiidian.test;

import org.junit.Test;

import com.yiidian.proxy.JDKProxyUtils;
import com.yiidian.service.CustomerService;
import com.yiidian.service.impl.CustomerServiceImpl;
/**
 * @author http://www.yiidian.com
 *
 */
public class Demo1 {
	
	@Test
	public void test1(){
		//目标对象
		CustomerService service = new CustomerServiceImpl();
		//获取JDK动态代理对象(接口代理)
		CustomerService proxy = (CustomerService)JDKProxyUtils.getProxy(service);
		//调用代理对象
		proxy.save();
		proxy.update();
	}
	
}

四、运行结果

从运行结果看出,CustomerService的save和update方法都成功在执行之前,切入了日志代码。

五、案例分析

上面代码中,Proxy类的静态方法newProxyInstance()方法生成了一个对象,这个对象实现了CustomerService中指定的接口。返回值是CustomerService接口的实现类。

动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。

newProxyInstance()方法的参数
Proxy类的newInstance()方法有三个参数:
1、ClassLoader loader:它是类加载器类型,CustomerService.class.getClassLoader()就可以获取到ClassLoader对象,只要你有一个Class对象就可以获取到ClassLoader对象;

2、Class[] interfaces:指定newProxyInstance()方法返回的对象要实现哪些接口,没错,可以指定多个接口,例如上面例子只我们只指定了一个接口:Class[] cs = {CustomerService.class};

3、InvocationHandler h:它是最重要的一个参数!它是一个接口!它的名字叫调用处理器!上面例子中proxy代理对象是CustomerService接口的实现类对象,那么它可以调用save()和update()方法,其实无论你调用代理对象的什么方法,它都是在调用InvocationHandler的invoke()方法!

源码下载:http://pan.baidu.com/s/1eSfEEwa