动态代理
一.动态代理特点
字节码随用随创建,随用随加载。它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。
二.动态代理方式
1.基于接口的动态代理
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
2.基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
三.基于接口的动态代理的实现案例
1.提供一个接口:
2.提供一个实现类:
package com.xszx.dynamicProxy.baseInte;
/**
* @author Mr Z
*
*
* 厂家
*/
public class Producer implements ProducerInte {
public void salProduct(float money) {
System.out.println("销售产品,收钱"+money);
}
public void afterService(float money) {
System.out.println("提供售后服务,收钱"+money);
}
}
3.实现过程
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Mr Z
*
* 顾客
*
* newProxyInstance方法的参数:
* ClassLoader:类加载器
* 它是用于加载代理对象字节码;和被代理对象使用相同的类加载器。
* Class[]:字节码数组
* 用于让代理对象和被代理对象有相同的方法
* InvocationHandler:用于提供增强的代码。
* 写如何代理,通常使用匿名内部类
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
ProducerInte producerInte = (ProducerInte) 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 {
//提供增强代码
Object returnValue=null;
//1.获取方法执行的参数
Float money=(Float)args[0];
//2.判断当前的方法是否为销售
if ("saleProduct".equals(method.getName())){
returnValue=method.invoke(producer,money*0.8f);
System.out.println("经销商赚取差价:"+money*0.2f);
}
return returnValue;
}
});
producerInte.saleProduct(1000);
}
}
四.基于子类的动态代理
1.导入第三方jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.接口和实现类同上
3.实现代码
import com.xszx.dynamicProxy.baseInte.Producer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Mr Z
* @create 2021 01 2021/1/6 16:52
* 顾客
*
* create方法的参数:
* Class:字节码
* 它是用于指定被代理对象字节码
* Callback:用于提供增强的代码
* 一般写该接口的子接口实现类:MethodInterceptor
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
Producer cglibproducer= (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
*
* @param proxy
* @param method
* @param args
* 以上三个参数和基于接口的动态代理的参数相同
* @param methodProxy 当前执行方法代理对象
* @return
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增强代码
Object returnValue=null;
//1.获取方法执行的参数
Float money=(Float)args[0];
//2.判断当前的方法是否为销售
if ("saleProduct".equals(method.getName())){
returnValue=method.invoke(producer,money*0.8f);
System.out.println("经销商赚取差价:"+money*0.2f);
}
return returnValue;
}
});
cglibproducer.saleProduct(1000f);
}
}