动态代理
- 在程序运行时,创建代理类的代理方式被称为动态代理
- 分类:
- jdk动态代理是利用java反射机制(java.lang.reflect包)
- cglib动态代理底层则是借助asm来实现的
- 好处:
- 在不改变程序源码的基础上,对代码进行增强或者屏蔽
- 动态代理的前提:必须有接口
JDK动态代理
原理
入门
- 接口
public interface Sing {
public abstract void sing();
}
- 被代理类
public class Singer implements Sing {
@Override
public void sing() {
System.out.println("XXX歌手唱歌");
}
}
- 代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Sing obj;
public MyInvocationHandler() {
super();
}
public MyInvocationHandler(Sing obj) {
super();
this.obj = obj;
}
/*
* Object proxy:代理类对象,和我们无关
* method:要增强的方法对象:sing()
* Object[] args:增强的方法需要的参数,没有忽略
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用没有增强之前的方法
Object result = method.invoke(obj, args);
System.out.println("跳舞");
System.out.println("捐款");
return result;// 原来的方法返回什么,这里还返回什么
}
}
- 测试类
import java.lang.reflect.Proxy;
public class Demo01_Proxy {
public static void main(String[] args) {
Sing singer = new Singer();
System.out.println("*******************代理之前的方法*******************");
singer.sing();
System.out.println("*******************代理之后的方法*******************");
singer = myProxy(singer);
singer.sing();
}
private static Sing myProxy(Sing singer) {
// 获取被代理类的类加载器
ClassLoader loader = Singer.class.getClassLoader();
// 获取被代理类实现的接口列表
Class<?>[] interfaces = Singer.class.getInterfaces();
/*
* ClassLoader loader:被代理类的类加载器
* Class<?>[] interfaces:被代理类实现的接口列表
* java.lang.reflect.InvocationHandler h
*/
singer = (Sing) Proxy.newProxyInstance(loader, interfaces, new MyInvocationHandler(singer));
return singer;
}
}
- 执行结果
案例
案例1
- 题目:求任意一个方法的运行时间
- 接口
public interface RunCode {
public abstract void run();
}
- 被代理类
public class Demo01 implements RunCode {
@Override
public void run() {
int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += i;
}
System.out.println("0-1000的和:"+sum);
}
}
- 代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private RunCode obj;
public MyInvocationHandler() {
super();
}
public MyInvocationHandler(RunCode obj) {
super();
this.obj = obj;
}
/*
* Object proxy:代理类对象,和我们无关 Method
* method:要增强的方法对象:sing()---->getMethod("sing"); Object[] args:增强的方法需要的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Long t1 = System.currentTimeMillis();
// 调用没有增强之前的方法
Object result = method.invoke(obj, args);
Long t2 = System.currentTimeMillis();
System.out.println("消耗时间" + (t2 - t1)+"毫秒");
return result;// 原来的方法返回什么,这里还返回什么
}
}
- 测试类
import java.lang.reflect.Proxy;
public class TestDemo {
public static void main(String[] args) {
// 1.创建被代理类对象
RunCode rc = new Demo01();
rc = myProxy(rc);
rc.run();
}
private static RunCode myProxy(RunCode rc) {
RunCode proxyRc = (RunCode) Proxy.newProxyInstance(rc.getClass().getClassLoader(),
rc.getClass().getInterfaces(),
new MyInvocationHandler(rc));
return proxyRc;
}
}
- 执行结果
案例2
- 模拟Collections中的:public static <T> List<T> unmodifiableList(List<? extends T> list)
- 方法使用案例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo01Proxy {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("java");
list = Collections.unmodifiableList(list);
//list.add("world");// java.lang.UnsupportedOperationException
//list.remove("hello");// java.lang.UnsupportedOperationException
System.out.println(list.size());
}
}
- 动态代理实现
- 接口(不用写,使用java.util.List)
- 被代理类(不用写,使用java.util.ArrayList)
- 代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
public class MyInvocationHandler<T> implements InvocationHandler {
private List<T> obj;
public MyInvocationHandler() {
super();
}
public MyInvocationHandler(List<T> obj) {
super();
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 抛出运行时异常
if (method.getName().equals("add")) {
throw new RuntimeException("add方法不可用");
}
if (method.getName().equals("remove")) {
throw new RuntimeException("remove方法不可用");
}
if (method.getName().equals("set")) {
throw new RuntimeException("set方法不可用");
}
// 如果是其他方法,直接调用
Object result = method.invoke(obj, args);
return result;
}
}
- 测试类
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
// 使用动态代理
list = myProxy(list);
// list.add("world");//java.lang.RuntimeException: add方法不可用
System.out.println(list.size());
}
private static <T> List<T> myProxy(final List<T> list) {
@SuppressWarnings("unchecked")
List<T> proxyList = (List<T>) Proxy.newProxyInstance(list.getClass().getClassLoader(),
list.getClass().getInterfaces(), new MyInvocationHandler<T>(list));
return proxyList;
}
}