设计模式——代理模式

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子

用图表示如下:

 


4.1静态代理

定义一个接口,列出抽象方法

public interface CarInterf {

//造车

public abstract void makeCar();

//洗车

public abstract void washCar();

//修车

public abstract void fixCar();

//找车模

public abstract void findCarModel();

}

定义委托类,并且要继承接口

//委托方

public class CarFactory implements CarInterf {

@Override

public void makeCar() {

System.out.println("委托者造车方法");

}

@Override

public void washCar() {

System.out.println("委托者洗车方法");

}

@Override

public void fixCar() {

System.out.println("委托者修车方法");

}

@Override

public void findCarModel() {

System.out.println("委托者找车模方法");

}

}

定义一个通知类,用来扩充委托者的功能

public class MyAdvice {

public void beafore(){

System.out.println("前置通知");

}

public void after(){

System.out.println("后置通知");

}

//第一个参数为要增强的方法

//第二个参数为代理对象的class对象

public void around(String method,Class proxyCar) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{

System.out.println("环绕增强开始");

//得到要执行的方法

Method meth = proxyCar.getMethod(method, null);

//执行该方法

meth.invoke(proxyCar.newInstance(), null);

System.out.println("环绕增强结束");

}

}

 

定义一个代理类,并且继承同一接口

/*

* 代理方:

* 为委托方的功能添加额外功能,并且还不影响委托方中的代码结构

*/

public class ProxyCar implements CarInterf{

//通知对象

private static MyAdvice advice = new MyAdvice();

//委托者对象

private CarInterf carFacory;

public ProxyCar(CarInterf carFacory) {

this.carFacory = carFacory;

}

public ProxyCar() {

}

@Override

public void makeCar() {

// System.out.println("造车之前的额外功能");

advice.beafore();

//基本功能

this.carFacory.makeCar();

// System.out.println("造车之后的额外功能");

}

@Override

public void washCar() {

this.carFacory.washCar();

advice.after();

}

@Override

public void fixCar() {

try {

advice.around("fixCar", carFacory.getClass());

} catch (Exception e) {

e.printStackTrace();

}

}

@Override

public void findCarModel() {

}

}

测试类

@Test

public void test() {

//使用静态代理

ProxyCar proxyCar = new ProxyCar(carFactory);

proxyCar.makeCar();

proxyCar.fixCar();

proxyCar.washCar();

proxyCar.findCarModel();

}

 


 

4.2动态代理

定义一个接口,列出抽象方法

public interface CarInterf {

//造车

public abstract void makeCar();

//洗车

public abstract void washCar();

//修车

public abstract void fixCar();

//找车模

public abstract void findCarModel();

}

定义委托类,并且要继承接口

//委托方

public class CarFactory implements CarInterf {

@Override

public void makeCar() {

System.out.println("委托者造车方法");

}

@Override

public void washCar() {

System.out.println("委托者洗车方法");

}

@Override

public void fixCar() {

System.out.println("委托者修车方法");

}

@Override

public void findCarModel() {

System.out.println("委托者找车模方法");

}

}

定义一个动态代理类,需要继承InvocationHandler接口,在程序运行前要先加载委托方

/*

* 委托方是在运行时确定

* 动态代理 需要实现JDK提供的接口

* AOP使用的动态代理是 CGlib

* JDK动态代理内部实现是基于接口的

* CGlib动态代理内部实现还是基于委托对象

*/

 

public class DynamicProxy implements InvocationHandler{

//目标对象

private Object targetObj;

public DynamicProxy() {

}

public DynamicProxy(Object targetObj) {

this.targetObj = targetObj;

}

//将委托方和代理方建立动态联系

//返回值为代理对象

public Object instance(){

/*

* 第一个参数:对象的加载器(ClassLoader)在JVM中将.java源文件进行编译就生成.class文件,通过.class文件 创建当前实例对象

* 第二个参数:目标对象的所有接口方法

* 第三个参数:代理对象

*/

return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this);

}

/*

* 当代理对象调用委托对象的接口方法时,

* 并不是立即执行,而是执行该invoke方法。

* 第一个参数:代理对象

* 第二个方法:需要执行的方法

* 第三个参数:执行方法需要的实参

*/

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("前置通知");

//method方法的返回值

Object object = method.invoke(targetObj, args);

System.out.println("后置通知");

return object;

}

 

}

测试类

@Test

public void test() {

//动态代理

CarFactory carFactory = new CarFactory();

//代理CarFactory

DynamicProxy dynamicProxy = new DynamicProxy(carFactory);

//进行动态绑定,生成代理对象。

CarInterf object = (CarInterf)dynamicProxy.instance();

//当代理对象调用委托对象的接口方法时,先执行invoke()

object.washCar();

}

 

这里有一个坑!Spring AOP采用两种代理方法,一种是常规的JDK,一种是CGLIB。由于CarFactory实现了CarInterf接口,当代理对象实现了至少一个接口是,默认使用JDK动态代理。当代理对象没有实现任何接口是,就会使用CGLIB方法。在JDK动态代理中,代理对象必须强转为接口,不然会报错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值