代理:在实例的方法执行之前,由代理插入一段执行代码,然后调用实例的方法,之后也可以插入一段代码。这是AOP编程的核心。
在Java中实现动态代理有两种方式:
★ JDK动态代理 – 应用于代理实现了接口的类
★ cglib动态代理 – 主要应用于代理普通类(未实现接口)
先说说JDK动态代理
JDK动态代理主要依靠JavaAPI中的Proxy
类,这个类中有个重要的方法
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
这是这个方法的英文解释,供参考。
对上面的方法做个理解:
▷ ClassLoader loader
类加载器,加载被代理类的字节码。
▷ Class<?>[] interfaces
被代理类实现的接口,代理类要和被代理类有相同的行为
▷ InvocationHandler h
指定如何代理, 用到策略设计模式
案例一
//接口
public interface Human {
void sing(float money);
void dance(float money);
}
//实现类
public class SpringBrother implements Human {
public void sing(float money) {
System.out.println("拿到:"+money+" 元开始唱歌");
}
public void dance(float money) {
System.out.println("拿到:"+money+" 元开始跳舞");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client1 {
public static void main(String[] args) {
final Human sb = new SpringBrother();
//产生代理类,得到他的实例
Human proxyMan = (Human)Proxy.newProxyInstance(sb.getClass().getClassLoader(),
sb.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("sing".equals(method.getName())){
//唱歌
float money = (Float)args[0];
if(money>10000){
method.invoke(sb, money/2);
}
}
if("dance".equals(method.getName())){
//唱歌
float money = (Float)args[0];
if(money>20000){
method.invoke(sb, money/2);
}
}
return null;
}
}
);
proxyMan.sing(20000);
proxyMan.dance(100000);
}
}
运行结果:
拿到钱:10000.0开唱
拿到钱:50000.0开跳
InvocationHandler是调用处理程序,每个代理类都对应一个调用处理程序
它是个接口,里面只有一个invoke()方法,每个类对其都有不同的实现,用到了策略设计模式
Object invoke(Object proxy, Method method, Object[] args)
● Object proxy
对被代理对象的引用。
● Method method
调用了被代理对象的哪个方法
● Object[] args
当前方法用到的参数,没有则为null
再一个就是cglib动态代理
案例二
public class SpringBrother{
public void sing(float money) {
System.out.println("拿到:"+money+" 元开唱");
}
public void dance(float money) {
System.out.println("拿到:"+money+"元开跳");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Client1 {
public static void main(String[] args) {
final SpringBrother sb = new SpringBrother();
/*
Class type:代理类的父类型
Callback cb:回调,如何代理
*/
SpringBrother proxy = (SpringBrother) Enhancer.create(SpringBrother.class,new MethodInterceptor(){
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
//判断出场费
if("sing".equals(method.getName())){
//唱歌
float money = (Float)args[0];
if(money>10000){
method.invoke(sb, money/2);
}
}
if("dance".equals(method.getName())){
//唱歌
float money = (Float)args[0];
if(money>20000){
method.invoke(sb, money/2);
}
}
return null;
}
});
System.out.println(proxy instanceof SpringBrother);
proxy.dance(100000);
proxy.sing(50000);
}
}
运行结果:
拿到钱:50000.0 元开跳
拿到:25000.0 元开唱
参考有关动态代理的原理了解底层原理