目录
一、JDK动态代理
以下的事例是以统计方法运行的速度为例子,在原有的add,delete,update的方法上进行增强,即用动态代理来完成代码的增强,不改变原有的业务逻辑代码
1、定义业务接口和实现
public interface UserService {
public void addUser(String UserId, String password);
public void delUser();
public void updateUser();
}
public class UserServiceImp implements UserService {
@Override
public void addUser(String UserId, String password) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("添加账户成功");
}
@Override
public void delUser() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("delete--User---success");
}
@Override
public void updateUser() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("update---User---success");
}
}
2、定义动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 参数一:类加载器,负责加载被代理类到内存zhong
* 参数二:获取被代理对象的全部接口(被代理对象就是上面的UserServiceImp对象)
* 参数三:代理的核心处理逻辑,即加强的代码
*/
public class ProxyUtil {
/**
* 生成代理对象
* @param obj
* @return
*/
public static <T>T getProxy(T obj){
return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//参数一:代理对象的本身,一般不管
//参数二:被代理的方法
//参数三:被代理方法,应该传入的参数
long startTime = System.currentTimeMillis();
Object result = method.invoke(obj, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");
//把业务功能方法执行的结果返回给调用者
return result;
}
});
}
}
3、测试代码
public class Main {
public static void main(String[] args) {
UserService userService = ProxyUtil.getProxy(new UserServiceImp());
userService.addUser("admin","123456");
userService.delUser();
userService.updateUser();
}
}
注意:JDK实现动态代理要求被代理类必须实现接口,否则不能使用JDK动态代理。
二、CGLIB动态代理
被代理对象使用上面的实例
定义动态代理类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyCglibUtil {
public static <T>T getProxyInstance(T obj) {
// 创建代理类
return (T)Enhancer.create(obj.getClass(), // 设置被代理对象的类
new MethodInterceptor(){ //代理的核心逻辑
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//参数一:代理对象的本身,
//参数二:被代理的方法
//参数三:被代理方法,应该传入的参数
//参数四:代理方法
long startTime = System.currentTimeMillis();
Object result = methodProxy.invokeSuper(o, objects);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");
//把业务功能方法执行的结果返回给调用者
return result;
}
});
}
}
测试结果
三、总结
一、两者比较
JDK动态代理只能代理实现了接口的类,而CGLIB动态代理则没有这个限制。CGLIB动态代理是动态生成被代理类的子类,重写被代理类的方法,因此CGLIB动态代理不能代理final修饰的方法。
二、spring中的动态代理
springAOP集成了JDK动态代理和CGLIB动态代理,根据类是否实现了接口进行区分
在类实现接口时(下面UserServiceImpl实现了UserService),使用的是JDK动态代理