代理在我们的日常生活中,就有很多体现,房屋租赁代理,校园辅导班招生代理,化妆产品销售代理等。为什么我们要找代理呢,代理是专业的,是方便的。例如我们买一件化妆品,或买一本书,肯定是不能去找生产厂家买的,是要通过中间的代理商实现交易。
1.代理类是自己手工实现的,自己创建一个java类,表示代理类
2.同时也要实现你所要代理的目标
3.静态代理的优缺点
优点:
1)实现简单
2)容易理解
缺点:当你的项目中,目标类的代理类很多的时候,有一下的缺点
1)当目标类增加了,代理类可能也需要成倍的增加
2)当你的接口中功能在增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多
1)创建一个接口,定义图书销售的方法,表示厂家和当当网商家做的事情
2)创建厂家类,实现1步骤的接口
3)创建当当网商家类,就是代理,也需要实现1步骤中的接口
4)创建客户端类,调用当当网商家的方法买2本书,计算返回需要花费的价格
/**
* 定义一个卖书的接口,只对厂家和商家开放
*/
public interface SellBook {
/**
* 一次购买amount本书需要多少钱
* @param amount
* @return 总价
*/
double bookPrice(int amount);
}
/**
* 目标类:图书厂家,不接受用户的单独购买
*/
public class BookFactory implements SellBook{
/**
* 一本书定价25元,根据amount,可以实现不同的价格
* @param amount
* @return
*/
@Override
public double bookPrice(int amount) {
return 25.0 * amount;
}
}
/**
* 当当网是一个商家,代理图书的销售
*/
public class DangDangWang implements SellBook{
//声明代理的厂家
private BookFactory factory = new BookFactory();
/**
* 实现代理图书销售的功能,厂家给25元的单价,当当网赚钱可以加价10块销售(功能增强)
* @param amount
* @return
*/
@Override
public double bookPrice(int amount) {
//获取厂家原价
double originalPrice = factory.bookPrice(amount);
//代理商家为了赚钱,加价销售
double price = originalPrice + 10.0;
return price;
}
}
/**
* 静态代理测试
*/
public class StaticProxyTest {
public static void main(String[] args){
DangDangWang dd = new DangDangWang();
System.out.println("用户想买2本书,需要的价格是: " + dd.bookPrice(2) + "元");
}
}
1) 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
2) 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
3) 动态代理的实现方式常用的有两种:JDK动态代理和CGLlB动态代理(暂不介绍)。JDK动态代理是使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect里面有三个类:InvocationHandler,Method,Proxy
1)public interface InvocationHandler
InvocationHandler
是由代理实例的调用处理程序实现的接口 。每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
InvocationHandler接口(调用处理器):就一个方法 invoke()
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在
invoke()方法中。
代理类完成的功能
1)调用目标方法,执行目标方法的功能
2)功能增强,在目标方法调用时,增加功能
方法原型
/** * 处理代理实例上的方法调用并返回结果 * @param proxy jdk创建的代理对象,无需赋值。 * @param method 目标类中的方法,jdk提供的method对象 * @param args 目标类中方法的参数,jdk提供 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
2)Method
Method类: 表示目标类中的方法。
作用: 通过 Method可以执行某个目标类的方法, Method.invoke();
method.invoke(目标对象,方法的参数)
object res = method.invoke(service22,"李四")
说明: method.invoke()就是为了用来执行目标方法,等同于静态代理中
//向厂家发送订单,返回报价
double originalPrice = factory.bookPrice(amount);
3)Proxy类
proxy类:创建代理对象。之前创建对象都是new类的构造方法,现在我们是使用proxy类的方法,代替new的使用。
方法:静态方法 newProxyInstance()
作用是:创建代理对象,等同于静态代理中
DangDangWang dd = new DangDangWang();
方法原型:
/**
* 创建代理对象
* @param loader 类加载器
* @param interfaces 接口
* @param h 自己实现的代理类,要完成的功能
* @return
*/
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
参数介绍:
1) ClassLoader loader 类加载器,负责向内存中加载对象的,使用反射机制获取对象的classLoader,
如何获取类 a, 如:a.getCalss().getClassLoader(),目标对象a的类加载器
这里我们细分:每一个类都继承Object类,在Object中有一个getClass方法,表示类对象的运行时类的Class对象。而Class类里面有一个public ClassLoader getClassLoader()方法
2) Class>[] interfaces: 接口,目标对象实现的接口,也是反射获取的
3) InvocationHandler h : 自己实现的代理类,要完成的功能
返回值就是代理对象
1)创建接口,定义目标类要完成的功能
2)创建目标类实现接口
3)创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
4)使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型
1)创建接口,定义目标类所需功能
/**
* 定义一个卖书的接口,只对厂家和商家开放
*/
public interface SellBook {
/**
* 一次购买amount本书需要多少钱
* @param amount
* @return 总价
*/
double bookPrice(int amount);
}
2)创建目标类实现接口
/**
* 目标类:图书厂家,不接受用户的单独购买
*/
public class BookFactory implements SellBook{
/**
* 一本书定价25元,根据amount,可以实现不同的价格
* @param amount
* @return
*/
@Override
public double bookPrice(int amount) {
return 25.0 * amount;
}
}
3)创建Invocationhandler实现类.在invoke()方法中完成代理类的对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 实现InvocationHandler接口,实现代理类的功能
*/
public class BookHandle implements InvocationHandler {
//动态代理:目标对象是活动灵活的,不是固定的,传入哪个就创建哪个
private Object target = null;
/**
* 传入需要创建的目标对象
* @param target
*/
public BookHandle(Object target) {
this.target = target;
}
/**
* 处理代理实例上的方法调用并返回结果
* @param proxy jdk创建的代理对象,无需赋值。
* @param method 目标类中的方法,jdk提供的method对象
* @param args 目标类中方法的参数,jdk提供
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现代理
Object res = method.invoke(target,args);
//功能增强
if (res != null){
double price = (double) res;
res = price + 10.0;
}
return res;
}
}
4)使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* JDK动态代理测试
*/
public class DynamicProxyTest {
public static void main(String[] args){
//1.创建目标对象--JDK动态代理必须有
SellBook factory = new BookFactory();
//2.创建Invocationhandler对象,谁使用返回谁的对象
InvocationHandler bookHand = new BookHandle(factory);
//3.创建代理对象
SellBook proxy = (SellBook) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),bookHand);
System.out.println("商家订购2本书需要: " + proxy.bookPrice(2) + "元");
}
}
动态代理是一种创建java对象的能力,让你不用创建 DangDangWang类就能创建代理类对象,避免静态代理的缺点。动态代理中目标类即使很多,代理类数量仍然可以很少,当你修改了接口中的方法时,不会影响代理类。但是JDK动态代理有一个缺点,必须要有接口出现。如果没有接口,我们可以使用cglib动态代理实现。