文章目录
1、什么是动态代理?
- 动态代理就是根据对象在内存中加载的Class类创建运行时类对象,从而调用代理类方法和属性。
换句话说就是程序运行时通过反射得到一个对象类,再通过代理方法得到一个反射得到的类的被代理对象,该被代理对象可以调用被代理类方法和属性。
2、为什么需要有动态代理?
- 减少代码冗余。
- 避免冗余代码的混乱和分散。
3、什么情况下需要动态代理?
- 日志服务,日常程序的维护肯定少不了打日志,程序的每一个结点中的程序运行的每一刻发生的变化都需要日志的输出。对于每个结点打日志这项服务,可以统一通过配置在一个地方,通过动态代理即可在每个结点注入日志服务。
- 登录验证服务,登录验证服务一般都会使用拦截器,拦截器其实就是动态代理。在执行某方法请求之前先去执行别的方法,就是拦截下来,去执行我的登录验证服务(若用户已登录,则返回用户需访问的页面,若用户未登录,或是cookie失效,都需重新登录,返回登录页面。加上这个业务实现逻辑,觉得能加深老哥们的理解)。
- 等等还有许多。。
4、怎么实现动态代理?
可以看我的另一篇文章,文章链接:https://blog.csdn.net/weixin_44185736/article/details/105054454
就这么完事了?当然不是,正如你们所看到的下文。
下文不就是你的链接文章?你不会说就不会有老哥知道了。
其实是新东西啦,起码代码是新的,知识都是一样的嘛。
4.1 被代理类的接口
/**
* 对生产厂家要求的接口
*/
public interface IProducer {
/**
* 销售
* @param money
*/
public void saleProduct(float money);
/**
* 售后
* @param money
*/
public void afterService(float money);
}
4.2 被代理的类
/**
* 一个生产者
*/
public class Producer implements IProducer{
/**
* 销售
* @param money
*/
public void saleProduct(float money){
System.out.println("销售产品,并拿到钱:"+money);
}
/**
* 售后
* @param money
*/
public void afterService(float money){
System.out.println("提供售后服务,并拿到钱:"+money);
}
}
4.3 测试类
内部类代理实现invoke()方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 模拟一个消费者
*/
public class Client {
public static void main(String[] args) {
System.out.println("这里是卢本伟广场"+"\n"+"-----------------------------");
final Producer producer = new Producer();
/**
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于接口的动态代理:
* 涉及的类:Proxy
* 提供者:JDK官方
* 如何创建代理对象:
* 使用Proxy类中的newProxyInstance方法
* 创建代理对象的要求:
* 被代理类最少实现一个接口,如果没有则不能使用
* newProxyInstance方法的参数:
* ClassLoader:类加载器
* 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
* Class[]:字节码数组
* 它是用于让代理对象和被代理对象有相同方法。固定写法。
* InvocationHandler:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
*/
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 作用:执行被代理对象的任何接口方法都会经过该方法
* 方法参数的含义
* @param proxy 代理对象的引用
* @param method 当前执行的方法
* @param args 当前执行方法所需的参数
* @return 和被代理对象方法有相同的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理爸爸到此一游!!!");
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float)args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money*0.8f);
}
if ("afterService".equals(method.getName())){
returnValue = method.invoke(producer, money*0.8f);
}
System.out.println("代理爸爸到此二游!!!"+"\n");
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
proxyProducer.afterService(100f);
}
}
4.4 输出
这里是卢本伟广场
-----------------------------
代理爸爸到此一游!!!
销售产品,并拿到钱:8000.0
代理爸爸到此二游!!!
代理爸爸到此一游!!!
提供售后服务,并拿到钱:80.0
代理爸爸到此二游!!!
4.5 结构如下图
4.6 代理过程解析
敲黑板,重点,必考,我教过这么多届学生,就你们最吊,不好意思,跑题了。
- 通过下图看我写的序号,这就是测试类程序运行语句的运行的步骤,通过内部类来展示才能看得到这个效果,说到这,不把赞甩我脸上再走?
- 解读,从程序运行步骤来看,被代理类使用newProxyInstance得到的被代理类的代理对象(是不是有点绕口),就是代码中的proxyProducer对象它属入Producer对象,但它也是拥有代理方法的代理对象。(重点:)使用这个代理对象调用使用其被代理类的方法时,可以看到其会去执行invoke方法,这里就是动态代理的展现,若不写内部类,写一个对InvocationHandler接口的实现类,这时invoke也在该实现类,这样proxyProducer这个代理对象调用使用其被代理类的方法时就会去调用InvocationHandler接口的实现类中的invoke方法,InvocationHandler接口的实现类中只要我们传入不同的对象,我们就可以为不同的类进行代理,不用重复写invoke方法,这就是动态代理的作用。我们还可以在invoke方法中进行代码增强,所以说这就是动态代理!!
7、总结
不会有人还不懂动态代理吧,不会吧!!
若是不会正常,这文章其实是要体现出动态代理的价值所在和动态代理的流程,便于我们理解,各位读者老哥可以参考更多文章来充分认识到动态代理。
不懂得小伙伴可以留下评论,一起讨论哦!!