代理模式:
代理模式在Java中特别常见,如spring AOP功能就是用代理来实现的。代理模式作用是:在不修改被代理对象功能的基础上,通过对代理类进行扩展,进行一些功能上的附加与增强。
一般使用代理模式我们需要先定义一个接口,静态代理只是一种简单的java代码功能扩展。而动态代理利用了反射机制,使用更简单,但背后逻辑…先说明一点,动态代理代理的是接口,而不是类,Proxy类产生的代理对象是Proxy的一个实例,这个实例实现了我们定义的接口
静态代理:
举一个黄牛代理买票的例子:
public interface BuyTicket {
//买票
void buyTicket();
}
我自己买票,买不到
public class CommonPerson implements BuyTicket {
@Override
public void buyTicket() {
System.out.println("我自己在12306买不到票!");
}
}
我在智行火车票上加钱抢票,找黄牛代理
public class HuangNiu implements BuyTicket {
//我买不到票,我需要被代理
CommonPerson person = new CommonPerson();
@Override
public void buyTicket() {
person.buyTicket();
System.out.println("我是黄牛,买票找我,出票成功!");
}
public static void main(String[] args) {
HuangNiu huangNiu = new HuangNiu();
huangNiu.buyTicket();
}
}
打印结果:
可以看出,我们自己买不到票,找黄牛代理,代理类可以帮助我们实现功能增强。
动态代理(jdk):
动态代理通过java反射机制,获取某个被代理类的所有接口,并创建代理类。接口类和被代理类同上:
import Proxy.BuyTicket;
import Proxy.CommonPerson;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Description:
* Created by CWG on 2020/8/29 10:34
*/
public class HuangNiu implements InvocationHandler {
private CommonPerson person;
public HuangNiu(CommonPerson person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(person, args);
System.out.println("我是黄牛,买票找我,出票成功!");
return res;
}
public static void main(String[] args) {
//被代理类
CommonPerson person = new CommonPerson();
//代理类
HuangNiu huangNiu = new HuangNiu(person);
//生成代理对象:注意这里生成的代理对象只能是接口
BuyTicket buyTicket = (BuyTicket) Proxy.newProxyInstance(
CommonPerson.class.getClassLoader(),
CommonPerson.class.getInterfaces(),
huangNiu);
//调用代理对象方法
buyTicket.buyTicket();
}
}
打印结果:
可以发现功能与静态代理一样,不同的是静态代理每次都要重写接口中方法,而动态代理使我们免于去重写接口中的方法,着重于去扩展相应的功能或是方法的增强,虽然在此示例中可能看不出,可能看上去比静态代理更复杂,当我们在实际开发环境下,接口中方法很多的时候,就可以发现动态代理的便捷,会大大减少项目中的业务量。
动态代理解读:
Proxy类
在上例main测试方法中,用到了Proxy.newProxyInstance()方法。动态代理涉及了一个非常重要的类Proxy。正是通过Proxy的静态方法newProxyInstance才会动态创建代理
public static Object newProxyInstance(ClassLoader var0,
Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException
- ClassLoader var0:对应参数 CommonPerson.class.getClassLoader()即被代理类的类加载器
- Class<?>[] var1:对应参数 CommonPerson.class.getInterfaces()即获取被代理类实现的所有接口
- InvocationHandler var2:对应参数 代理类huangNiu, 为一个InvocationHandler实现对象
InvocationHandler接口
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
代理类需要实现InvocationHandler 接口,invoke()虽然没有被显式调用,但该方法也一定被执行了,对应的三个参数分别传入的是:代理类的实例,method是调用的方法,即需要执行的方法;args是方法的参数;
就本人目前水平,想看懂动态代理背后如何实现有点吃力,以后看懂再接着写吧,现在也只是知道动态代理是干嘛用的,如果有兴趣继续探究可以参考下面的参考文章3。
参考文章:
1、jdk动态代理与cglib动态代理实现原理
2、为什么要使用java动态代理
3、JDK的动态代理原理