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()方法!
热门文章
优秀文章