什么是动态代理呢?
动态代理其实是一种方便运行时候动态的处理代理方法的调用机制。
假如现在有一个生产者类IProducter,类内有两个方法: public void saleProducter(float money){ System.out.println("卖东西,拿钱"+money); }
和 public void afterServce(float money){ System.out.println("提供售后服务,拿钱"+money);}现在厂家为了减少运营成本通过代理商来代理销售和售后服务,
在增加了代理商后则必然要为代理商分一部分利润,那么原本的销售方法则必须要进行修改,假如要将售价的20%分给代理商
那就需要将原方法做如下修改:
public void saleProducter(float money){ System.out.println("卖东西,拿钱"+money0.8); }
那如果此时不想修改原方法又想实现该功能应该怎么办呢?
答案是:使用动态代理,在使用该方法时对该方法进行一个加强(即修改利润),那动态代理是如何实现对方法的加强而不修改原本的方法呢?
通过过滤方法如果谁使用了该方法在该类**加载到内存时**修改类的方法(随用随创建,随用随加载,随用随加强),从而达在不修改原类的情况下对类中的方法进行加强。
那有人可能要问了,这绕了一大圈还不如修改原类中的方法来的直接。
那么请你思考下一个问题,如果我们现在有一个顾客在买东西时想要得到一个购买时间,那应该怎么来实现呢?直接在原类的saleProducter方法中添加在记录调用该方法的时间的代码吗?
那如果有的顾客不需要这个时间呢?他却还是要执行获取事件的代码。如果现在有人买的东西出了问题要走售后又想要得到自己走售后的时间呢?还在原来的基础上修改吗?这显然不合合适。
这时我们可以通过动态代理为需要增强方法的那部分用户做一个增强而不需要的用户就不增强。
也可以通过动态代理同时为多个方法增强就不需要在原类中类修改多个方法。
同时也可以避免非业务逻辑的代码嵌入到我们的业务中,破坏了业务代码的纯粹性,把这个非业务的代码从业务代码中剥离出来,通过动态代理,我们可以将这些代码在动态运行的时候再加入它!
下面我们通过代码来讲解代理模式具体是怎么实现的
首先我们要知道代理模式分为两种一种是基于接口的代理和一种是基于子类的代理。首先介绍基于接口:
/**
*代理商
**/
package com.shuai.proxy;
/**
* 对生产厂家的要求
*/
public interface IProducer {
/**
* 销售
*
* @param money
*/
public void saleProducter(float money);
/**
* 售后
*
* @param money
*/
public void afterServce(float money);
}
package com.shuai.proxy;
/**
* 一个生产者
*/
public class Producer implements IProducer{
/**
*销售
* @param money
*/
public void saleProducter(float money){
System.out.println("卖东西,拿钱"+money);
}
/**
* 售后
* @param money
*/
public void afterServce(float money){
System.out.println("提供售后服务,拿钱"+money);
}
}
package com.shuai.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改方法的基础上对方法增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于接口的动态代理:
* 设计的类:Proxy
* 提供者:JDK官方
* 如何创建代理对象:
* 使用proxy类中的newProxyInstance方法
* 创建代理对象的要求:
* 被代理对象最少实现一个接口,否则不能使用
* newProxyInstance方法的参数:
* classLoader:类加载器
* 用于加载代理对象的字节码,和被代理对象使用相同的类加载器,固定写法
* class[] :字节码数组
* 它是让代理对象和被代理对象有相同的方法(接口),固定写法
* InvocationHandler:用于增强代码
* 他是让我们如何写代理,一般都是些该接口的实现类,通常情况下都是匿名内部类
* 但不是必须,此接口谁用谁写
*
*/
/**
* 模拟一个消费者
*/
public class Client {
public static void main(String[] args){
final Producer producer=new Producer();
//获取动态代理对象
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 {
//提供增强的代码
Object returnValue=null;
//1、获取方法执行的参数
Float money=(Float)args[0];
//2、判断当前方法是不是销售
if("saleProducter".equals(method.getName())){
returnValue =method.invoke(producer,money*0.8f);
}
return returnValue;
}
});
proxyProducer.saleProducter(1000f);
}
}
介绍基于子类:
package com.shuai.cglib;
/**
* 一个生产者
*/
public class Producer{// implements IProducer{
/**
*销售
* @param money
*/
public void saleProducter(float money){
System.out.println("卖东西,拿钱"+money);
}
/**
* 售后
* @param money
*/
public void afterServce(float money){
System.out.println("提供售后服务,拿钱"+money);
}
}
package com.shuai.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 模拟一个消费者
*/
public class Client {
public static void main(String[] args){
final Producer producer=new Producer();
/*
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改方法的基础上对方法增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于子类的动态代理:
* 设计的类:Proxy
* 提供者:第三方sglib
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理对象不是最终类
* newProxyInstance方法的参数:
* calss:字节码
* 它是用于指定被代理对象的字节码
* callback:用于提供增强代码
* 它是让我们写如何代理.我们一般都是一些通过接口的实现类,通常情况下都是匿名内部类
* 此接口的实现类谁用谁写
* 我们一般写的是该接口的子接口的实现类:methodInterceptor 方法拦截
*/
Producer cglibProducer=(Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的所有方法都会经过该方法
* @param proxy
* @param method
* @param args
* 以三个参数和基于动态代理中invoke方法的参数一样
* @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("saleProducter".equals(method.getName())){
returnValue =method.invoke(producer,money*0.8f);
}
return returnValue;
}
});
cglibProducer.saleProducter(1200f);
}
}
以上为个人学习总结,若有不合理之处大佬多担待。
参考文章:谈谈动态代理?