JDK动态代理及简单实践
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
基于接口的动态代理
package com.itheima.proxy;
/**
* @author shkstart
* @create 2020-12-04 22:11
*/
public interface IProducer {
/**
* 销售方法
*/
public void saleProduct(float money);
/**
* 售后方法
*/
public void afterService(float money);
}
在这里package com.itheima.proxy;
/**
* 一个生产者
*/
public class Producer implements IProducer{
/**
* 销售
*/
public void saleProduct(float money){
System.out.println("销售产品,并拿到钱"+money);
}
/**
* 售后
*/
public void afterService(float money){
System.out.println("提供售后服务,并拿到钱"+money);
}
}
package com.itheima.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 模拟一个消费者
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
/**
* 动态代理
* 特点:字节码随用随创建,随用随加载
* 作用:在不修改源码的情况下对源码进行增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于接口的动态代理:
* 涉及的类:proxy
* 提供者:JDK
* 如何创建代理对象:
* 使用proxy类中的newProxyInstance方法
* 创建代理对象的要求:
* 被代理的类至少实现一个接口,否则不能使用
* newProxyInstance方法的参数:
* ClassLoader:类加载器
* 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法
* Class[]:字节码数组
* 它是用于让代理对象和被代理对象有相同的方法。固定写法
* InvocationHandler:用于提供增强代码
* 它是让我们写如何代理。我们一般都是写一些该接口的实现类,通常情况下都是匿名内部类,但不必须
* 此接口的实现类都是谁写谁
* 当内部匿名类访问外部成员变量时,要求是final
*/
IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
/**invoke()方法
* 作用:执行被代理对象的任何接口对象的方法都会经过该方法。有拦截的功能
* 方法参数的含义:
* proxy 代理对象的引用
* method 当前执行的方法
* 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);
}
// return method.invoke(producer,args);
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
}
}
程序结果:
销售产品,并拿到钱8000.0
基于子类的动态代理
首先需要引入cglib的jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
package com.itheima.cglib;
import com.itheima.proxy.IProducer;
/**
* 一个生产者
*/
public class Producer {
/**
* 销售
*/
public void saleProduct(float money){
System.out.println("销售产品,并拿到钱"+money);
}
/**
* 售后
*/
public void afterService(float money){
System.out.println("提供售后服务,并拿到钱"+money);
}
}
package com.itheima.cglib;
import com.itheima.proxy.IProducer;
import com.itheima.proxy.Producer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 模拟一个消费者
* 动态代理的优势:
* 连接池
* 解决全栈中文乱码的request方法增强
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
/**
* 动态代理
* 特点:字节码随用随创建,随用随加载
* 作用:在不修改源码的情况下对源码进行增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于子类的动态代理:
* 涉及的类:Enhancer
* 提供者:第三方jar包
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理的类不能是终极类,及被final关键字修饰
* create方法的参数:
* Class:字节码
* 它是用于指定被代理对象的字节码。
* callback:用于添加增强代码
* 它是让我们写如何代理。我们一般都是写一些该接口的实现类,通常情况下都是匿名内部类,但不必须
* 此接口的实现类都是谁写谁
* 我们一般写的都是该接口的子接口实现类:MethodInterceptor
* 当内部匿名类访问外部成员变量时,要求是final
*/
Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* invoke()方法
* 作用:执行被代理对象的对象的任何方法都会经过该方法。有拦截的功能
* 方法参数的含义:
* proxy 代理对象的引用
* method 当前执行的方法
* args 当前执行方法所需要的参数
* MethodProxy 当前执行方法的代理对象
* throws Throwable
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//此处添加增强代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float) args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())){
returnValue = method.invoke(producer,money*0.8f);
}
// return method.invoke(producer,args);
return returnValue;
}
});
cglibProducer.saleProduct(10000f);
}
}
程序结果:
销售产品,并拿到钱8000.0
通过这个简单的列子也可以大致了解基于接口的动态代理和基于子类的动态代理。在生产者与消费者例子中,分别通带代理模式,对其生产者的saleProduct(float money)方法经行了增强(也就是为生产者与消费者之间添加了代理商的职位)。
时间有限,有不足的地方希望大家多多补充。