当我们在写代码中需要对源码的方法进行增强,但是我们又不可以改源码。这个时候我们就可以使用代理的方式,当然代理的方式:静态代理和动态代理。但是静态代理我们需要创建很多代理类很是繁琐,而动态代理就是,随用随创建,随用随加载。动态代理可以分为:基于接口的动态代理,基于子类的动态代理。
在B站看到黑马老师讲的动态代理,推荐去看下。
基于接口的动态代理
基于接口的动态代理可以使用JDK官方提供的Proxy类,该类的newProxyInstance方法。
newProxyInstance方法的参数:
- ClassLoader:类加载器
- 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
- Class[]:字节码数组
- 它是用于让代理对象和被代理对象有相同方法。固定写法。
-
InvocationHandler:用于提供增强的代码
- 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。此接口的实现类都是谁用谁写。
下面是我们创建的三个类:Produce是工厂实现类,他实现了IProduce接口,
IProduce是工厂所需要满足的规范。client是一个客户。之前客户需要买一个东西可以直接找到厂商,可以直接购买。而现在厂商不在负责个人销售和售后,而是交给了经销商,现在客户购买商品就要从经销商出,所有的售后也直接找经销商。经销商就可以看做工厂的代理类,它需要强化工厂的一些方法。
IProduce
package proxy;
/**
* @File : IProduce.Java
* @Modify Time @Author @Version @Desciption
* ------------ ------- -------- -----------
* 2021-01-06 yudong 1.0 None
*/
public interface IProduce {
/**
* 销售
*
* @param money
*/
public void saleProduct(float money);
/**
* 售后
*
* @param money
*/
public void afterService(float money);
}
Produce
package proxy;
/**
* @File : Produce.Java
* @Modify Time @Author @Version @Desciption
* ------------ ------- -------- -----------
* 2021-01-06 yudong 1.0 None
*/
public class Produce implements IProduce {
/**
* 销售
*
* @param money
*/
@Override
public void saleProduct(float money) {
System.out.println("销售产品,并拿到钱" + money);
}
/**
* 售后
*
* @param money
*/
@Override
public void afterService(float money) {
System.out.println("提供售后服务,并拿到钱" + money);
}
}
Client:我们假设经销商需要抽成20%
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @File : Client.Java
* @Modify Time @Author @Version @Desciption
* ------------ ------- -------- -----------
* 2021-01-06 yudong 1.0 None
*/
public class Client {
public static void main(String[] args) {
Produce produce = new Produce();
IProduce proxyProduce = (IProduce) Proxy.newProxyInstance(produce.getClass().getClassLoader(),
produce.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 作用:执行被代理对象的任何接口方法都会经过该方法
* 方法参数的含义
* @param proxy 代理对象的引用
* @param method 当前执行的方法
* @param args 当前执行方法所需的参数
* @return 和被代理对象方法有相同的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增强的代码
Object reValue = null;
float money = (float) args[0];
if ("saleProduct".equals(method.getName())) {
reValue = method.invoke(produce, money * 0.8f);
}
return reValue;
}
});
proxyProduce.saleProduct(10000);
}
}
基于子类的动态代理
基于子类的动态代理不可是由final修饰的类,即不可被继承的类。其实写动态代理主要就是写动态代理的方法。
package cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import proxy.IProduce;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @File : Client.Java
* @Modify Time @Author @Version @Desciption
* ------------ ------- -------- -----------
* 2021-01-06 yudong 1.0 None
*/
public class Client {
public static void main(String[] args) {
Produce produce = new Produce();
/**
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于子类的动态代理:
* 涉及的类:Enhancer
* 提供者:第三方cglib库
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理类不能是最终类
* create方法的参数:
* Class:字节码
* 它是用于指定被代理对象的字节码。
*
* Callback:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
* 我们一般写的都是该接口的子接口实现类:MethodInterceptor
*/
Produce proxyProduce = (Produce) Enhancer.create(produce.getClass(),
new MethodInterceptor() {
/**
*
* @param o 代理对象的引用
* @param method 当前执行的方法
* @param objects 当前执行方法所需的参数
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//提供增强的代码
Object reValue = null;
float money = (float) objects[0];
if ("saleProduct".equals(method.getName())) {
reValue = method.invoke(produce, money * 0.8f);
}
return reValue;
}
}
);
proxyProduce.saleProduct(10000);
}
}