1 特点:字节码随用随创建,随用随加载
2 作用:不修改源码的基础上对方法增强
3 分类:
- 基于接口的动态代理
- 基于子类的动态代理
3.1 基于接口的动态代理:
- 涉及的类:Proxy
- 提供者:JDK官方
3.1.2 如何创建代理对象:
使用Proxy类中的newProxyInstance方法
3.1.3 创建代理对象的要求:
被代理类最少实现一个接口,如果没有则不能使用(此细节最重要)
3.1.4 newProxyInstance方法的参数:
(1) ClassLoader:类加载器 ,它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
(2) Class[]:字节码数组,它是用于让代理对象和被代理对象有相同方法。固定写法。
(3) InvocationHandler:用于提供增强的代码,它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的(此接口的实现类都是谁用谁写)。
详情可以查看类中的描述
3.1.5 分销和直销
(1) 直销:
用户直接从厂家购买商品,并由厂家提供售后,省去中间环节
(2) 分销:
在电商出现之前,我们大部分都是从分销商手中购买商品,并且通过分销商给我们提供售后服务
两种方式各有利弊,需要具体行业具体分析,再次不在赘述。
下面我们通过一个分销的方式来说明动态代理的实现方式
这里的经销商就起到一个代理的作用:
/**
* 对生产商提供的要求
*/
public interface IProducer {
/**
* 生产商需要具有销售的功能
* @param money
*/
public void saleProduct(float money);
/**
* 需要提供售后支持功能
* @param money
*/
public void afterService(float money);
}
/**
* 一个生产者
*/
public class ProducerImpl implements IProducer{
public void saleProduct(float money) {
System.out.println("销售产品,并拿到钱"+money);
}
public void afterService(float money) {
System.out.println("提供售后,并拿到钱"+money);
}
}
/**
* 模拟一个消费者
*/
public class Client {
public static void main(String[] args) {
//内部类需要访问所以需要定位为final类型
final ProducerImpl producer = new ProducerImpl();
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.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类型接收
Object returnValue = null;
//1. 获取方法执行的参数
Float money = (float) args[0];
//2. 判断当前方法是不是销售
if ("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money);
}
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
}
我们没有对ProductImpl做任何的操作就完成了商品的销售,那这种方式就是动态代理接口的实现方式,那如果我们把 IProducer proxyProducer = (IProducer) Proxy.newProxyInstance();换成 ProducerImpl proxyProducer = (ProducerImpl) Proxy.newProxyInstance 还可以实现动态搭理么,答案是否定的,如果我们一定要通过这种方式那又如何实现呢
3.2 基于子类的动态代理:
3.2.1 首先我们需要添加依赖
CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。CGLib 比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法。
CGLib 的底层是Java字节码操作框架 —— ASM。
<!--底层为字节码框架asm,不仅可以代理接口而且还可以代理普通类-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
这里我们可以看到asm的jar包已经为我们导入进来了
3.2.1 基于子类的动态代理:
- 涉及的类:Enhancer
- 提供者:第三方cglib
3.2.2 如何创建代理对象:
使用Enhancer类中的create方法
3.2.3 创建代理对象的要求:
被代理类不能是最终类
3.2.4 create方法的参数:
(1) Class:指定一个类的字节码 它是用于指定被代理对象的字节码,要想搭理谁就写谁的xx.class。固定写法。
(2) callback:用于提供增强的代码它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。我们一般写的都是该接口子接口实现:MethodInterceptor
代码实现`
/**
* 一个生产者
*/
public class Producer{
/**
* 销售
* @param money
*/
public void saleProduct(float money){
System.out.println("销售产品,并拿到钱:"+money);
}
/**
* 售后
* @param money
*/
public void afterService(float money){
System.out.println("提供售后服务,并拿到钱:"+money);
}
}
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
Producer cglibProducer = (Producer)Enhancer.create(Producer.class, 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类型的对象
Object returnValue = null ;
//接收参数
Float money = (Float) objects[0];
if("saleProduct".equals(method.getName())){
returnValue = method.invoke(producer,money*0.8f);
}
return returnValue;
}
});
cglibProducer.saleProduct(10000f);
}
}
以上两种代理都可以对我们已有的方法进行增强,添加我们需要的内容
那这个动态代理我们可以用在什么呢
- 全站中文乱码的问题
- 连接池中close(),不能真正的关闭,可以使用方法增强实现真正的关闭