文章目录
1.代理设计模式是什么?
Proxy Pattern。所谓代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。
如客户买电脑。
&&以前的模式:客户直接找厂家买。
&&使用了代理模式后:代理商找厂家拿货,由代理商卖电脑给客户,代理商给客户提供一些售后服务(解决不了得问题再拿回给厂家)。
如:
interface IProduct{ //产品(即接口)
public void sell();
}
class Producer implements IProduct{ //厂家(即真实主题)
public void sell() {
System.out.println("客户取得商品(真实主题)");
}
}
class Proxy implements IProduct{ //代理商(即代理主题)
private IProduct product;
public Proxy(IProduct product){ //设置代理的真实操作
this.product=product; //设置代理的子类
}
public void afterServiece() {
System.out.println("售后服务(代理主题)");
}
public void sell() {
this.afterServiece(); //调用与具体业务相关的操作
this.product.sell(); //调用厂家(真实主题)操作
}
}
public class Demo { //客户
public static void main(String[] args)throws Exception {
IProduct product =null;
product=new Proxy(new Producer());//实例化代理,同时传入代理的真实操作
product.sell();
}
}
以上代码使用的就是静态代理模式。
代理设计模式基本结构:①接口②真实主题③代理主题④主类。
2.为什么要有代理设计模式?
①为了解决直接访问对象时带来的问题。当两个类需要通信时,引入第三方代理类,将两个类的关系解耦。②不修改源码的基础上对方法增强。
这样客户只需要了解代理类即可。
3.代理设计模式如何使用?
首先,先明确代理设计模式分为静态代理和动态代理。
4.既然有了静态代理为什么还要有动态代理?
静态代理设计模式的缺点:当代理功能比较多时,代理类中方法需要写很多,维护也比较困难。(接口一旦改变,代理类也需要改变)
动态代理设计模式,就是为了解决上述问题。
5.它们的区别:
静态:在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成,即字节码随用随创建,随用随加载。
6.动态代理模式:
(1)基于接口的动态代理:
涉及的类:Proxy
提供者:JDK官方
如何创建代理对象:使用Proxy类中的newProxyInstance方法
创建代理对象的要求:被代理类最少实现一个接口,如果没有则不能使用。
newProxyInstance方法的参数:
ClassLoader:类加载器
它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法
Class[]:字节码数组
它是用于让代理对象和被代理对象有相同的方法。固定写法。
InvocationHander:用于提供增强的代码
它是让我们写如何代理。我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
此接口的实现类都是谁用谁写。
此方法的参数在下面代码中有说明。
Producer接口:
package com.proxy;
//对生产厂家要求的接口
public interface IProducer {
public void saleProduct(float money);
public void afterService(float money);
}
Producer类:
package com.cglib;
import com.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.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();
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 returnValue =null;
//1.获取方法执行的参数
Float money=(Float)args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())) {
returnValue= method.invoke(producer, money*0.8f);
}
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
}
}
//执行结果:销售产品并拿到钱,8000.0
(2)基于子类的动态代理:
涉及的类:Enhancer
提供者:第三方cglib库
如何创建代理对象:使用Enhancer类中的create方法
创建代理对象的要求:被代理类不能是最终类(被final修饰的类,不可继承的类)
create方法的参数:
Class:字节码
它是用于指定被代理对象的字节码
Callback:用于提供增强的代码
它是让我们写如何代理。我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
此接口的实现类都是谁用谁写。
我们一般写的都是该接口的子接口实现类:MethodInterceptor
Producer类:
package com.cglib;
import com.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.cglib;
import com.proxy.IProducer;
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;
//模拟一个消费者
public class Client {
public static void main(String[] args) {
final Producer producer =new Producer();
Producer cglibProducer =(Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* @param proxy
* @param method
* @param args
* ------以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[]args, MethodProxy methodProxy) 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 returnValue;
}
});
cglibProducer.saleProduct(12000f);
}
}
(3)说明:
其实无论是基于接口还是基于子类的动态代理,只要掌握了方法(newProxyInstance|create)的参数,基本就会了。