动态代理主要分为两种:1、基于接口的动态代理;2、基于子类的动态代理;接下来就对这两种代理方式的使用进行介绍。
1、基于接口的动态代理
IActor 接口:
public interface IActor {
/**
* 基本表演
* @param money
*/
public void basicAct(float money);
/**
* 危险的表演
* @param money
*/
public void dangerAct(float money);
}
Actor类:
public class Actor implements IActor {
/**
* 基本表演
* @param money
*/
public void basicAct(float money) {
System.out.println("开始基本表演:" + money);
}
/**
* 危险的表演
* @param money
*/
public void dangerAct(float money) {
System.out.println("开始危险表演:" + money);
}
}
Client:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
/**
* 模拟一个剧组
* @param args
*/
public static void main(String[] args) {
final Actor actor=new Actor();
/**
* 动态代理:
* 作用:再不改变源码的基础上,对已有的方法进行增强(它是AOP思想的实现技术)
* 分类:
* 1)基于接口的动态代理
* 要求:被代理类最少实现一个接口。
* 提供者:JDK官方
* 涉及的类:Proxy
* 创建代理对象的方法:newProxyInstance(ClassLoader, Class[], InvocationHandler)
* 参数含义:ClassLoader:类加载器;和被代理对象使用相同的类加载器。一般固定写法
* Class[]:字节码数组。被代理类实现的接口。(要求代理对象与被代理对象具有相同的行为)
* InvocationHandler(策略模式):一个接口,用于提供增强代码的。一般写一个该接口的实现类。实现类可以为匿名内部类。
* 策略模式:
* 使用要求:数据已经有了、目的明确、达成目标的过程就是策略。
* 在dbutils中的ResultSetHandler就是策略的具体应用。
*/
IActor proxyActor=(IActor) Proxy.newProxyInstance(actor.getClass().getClassLoader(),
actor.getClass().getInterfaces(), new InvocationHandler() {
/**
* 执行被代理对象的任何方法都会经过该方法,该方法有拦截功能。
* 方法参数:
* Object proxy:代理对象的引用。不一定每次都会用
* Method method:当前执行的方法。
* Object[] args:当前执行方法所需的参数。
* 返回值:当前执行方法的返回值。
*
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object rtValue=null;
//1、取出执行方法中的参数
Float money=(Float) args[0];
//2、判断当前执行的是什么方法
if ("basicAct".equals(method.getName())) {
//基本演出
if (money>10000) {
//执行方法
rtValue=method.invoke(actor, args);
}else {
System.out.println("给钱太少,不能表演!");
}
}
if ("dangerAct".equals(method.getName())) {
//危险演出
if (money>50000) {
//执行方法
rtValue=method.invoke(actor, args);
}else {
System.out.println("给钱太少,不能表演!");
}
}
return rtValue;
}
});
proxyActor.basicAct(10000f);
proxyActor.dangerAct(60000f);
}
}
2、基于子类的动态代理
IActor接口和Actor类与第一种情况一致,这里就不赘述了;
Client:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import proxy.IActor;
public class Client {
/**
* 模拟一个剧组
* @param args
*/
public static void main(String[] args) {
final Actor actor=new Actor();
/**
* 动态代理:
* 作用:再不改变源码的基础上,对已有的方法进行增强(它是AOP思想的实现技术)
* 2)基于子类的动态代理:
* 需要用到的两个jar包:
* 1)asm-4.0.jar
* 2)cglib-2.2.1.jar
* 要求:被代理的类不能是最终类。 不能被final修饰。
* 提供者:第三方CGLib
* 涉及的类:Enhancer
* 创建代理对象的方法:create(Class,Callback);
* 参数的含义:
* Class:被代理对象的字节码
* Callback:如何代理,也是一个接口,我们一般使用该接口的子接口;与InvocationHandler作用一样。
*/
Actor cglibActor=(Actor) Enhancer.create(actor.getClass(),new MethodInterceptor(){
/**
* 执行被代理对象的任何方法都会经过该方法,该方法有拦截功能。
* 方法的参数:
* 前面三个和invoke方法的参数含义和作用都一样。
* MethodProxy methodProxy:当前执行方法的代理对象。一般不用
*
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object rtValue=null;
//1、取出执行方法中的参数
Float money=(Float)args[0];
//2、判断当前执行的是什么方法
if ("basicAct".equals(method.getName())) {
//基本演出
if (money>10000) {
//执行方法
rtValue=method.invoke(actor, args);
}
}
if ("dangerAct".equals(method.getName())) {
//危险演出
if (money>50000) {
//执行方法
rtValue=method.invoke(actor, args);
}
}
return rtValue;
}
});
cglibActor.basicAct(50000f);
cglibActor.basicAct(100000f);
}
}