代理模式

设计模式之简单讨论

1:代理模式

意图:对其他对象提供一种代理以控制对这个对象的访问。例如 律师

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

 

2:代理模式的UML图

 

 

 

UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。

 

 

 

3:代理模式的实现

代理模式可以有两种实现的方式,一种是静态代理类,另一种是动态代理

静态代理代码示例如下

Subject接口的实现

public interface Subject {

    void visit();

}

实现了Subject接口的两个类:

public class RealSubject implements Subject {

    private String name = "xpfuser";

    @Override

    public void visit() {

        System.out.println(name);

    }

}

public class ProxySubject implements Subject{

 

    private Subject subject;

    public ProxySubject(Subject subject) {

        this.subject = subject;

    }

 

    @Override

    public void visit() {

        subject.visit();

    }

}

 

 

具体的调用如下:

public class Client {

    public static void main(String[] args) {

    ProxySubject subject = new ProxySubject(new RealSubject());

    subject.visit();

    }

}

通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。同时符合开闭原则但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

 

静态代理模式的特点一个主题类与一个代理类一一对应

 

 

4:动态代理

动态代理也分为两种:JDK代理、CGLIB代理

4.1JDK代理实现

核心技术 反射、接口

//1. 抽象主题

public interface Moveable {

  void move() throws Exception;

}

//2. 真实主题

public class Car implements Moveable {

  public void move() throws Exception {

    Thread.sleep(new Random().nextInt(1000));

    System.out.println("汽车行驶中…");

  }

}

//3.事务处理器

public class TimeHandler implements InvocationHandler {

  private Object target;

  public TimeHandler(Object target) {

    super();

    this.target = target;

  }

  /**

   * 参数:

   *proxy 被代理的对象

   *method 被代理对象的方法

   *args 方法的参数

   * 返回:

   *Object 方法返回值

   */

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

    long start-time = System.currentTimeMillis();

    System.out.println("汽车开始行驶…");

    method.invoke(target, args);

    long stopTime = System.currentTimeMillis();

    System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");

    return null;

  }

}

//测试类

public class Test {

  public static void main(String[] args) throws Exception{

//真实主题

Car car = new Car();  

//InvocationHandler

InvocationHandler h = new TimeHandler(car);

//真实主题class

    Class<?> cls = car.getClass();

    /**

     *loader 类加载器

     *interfaces 实现接口

     *h InvocationHandler

     */

//Moveable m 这个对象已经是被jvm修饰过的 已经不再是真实意义上的Moveable 类型。是Moveable 类型的代理类。可以在调用自己方法时 回调到动态代理类 TimeHandlerinvoke方法  已完成动态代理

Moveable m = (Moveable) Proxy.newProxyInstance

(cls.getClassLoader(),cls.getInterfaces(), h);

//调用方法 此时会真正的执行TimeHandler invoke方法

m.move(); }

}

JDK动态代理步骤

1.创建一个实现InvocationHandler接口的类,它必须实现invoke()方法

2.创建被代理的类及接口

3.调用Proxy的静态方法,创建一个代理类

4.通过代理调用方法

 

4.2:CGLIB代理:

继承式代理

有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做Cglib代理。

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,为其提供方法的interception(拦截),例如大家所熟知的Spring AOP。

 

特点:

1.代理的类不能为final,否则报错

2.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

 

public class test {

public static void main(String[] args) {

//目标对象

UserDao target = new UserDao();

//代理对象

UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();

//执行代理对象的方法

proxy.save();

}

}

/**

* 目标对象,没有实现任何接口

*/

class UserDao {

public void save() {

System.out.println("----已经保存数据!----");

}

}

/**

* Cglib子类代理工厂

* 对UserDao在内存中动态构建一个子类对象

*/

class ProxyFactory implements MethodInterceptor {

// 维护目标对象

private Object target;

public ProxyFactory(Object target) {

this.target = target;

}

// 给目标对象创建一个代理对象

public Object getProxyInstance() {

//1.工具类

Enhancer en = new Enhancer();

//2.设置父类

en.setSuperclass(target.getClass());

//3.设置回调函数

en.setCallback(this);

//4.创建子类(代理对象)

return en.create();

}

@Override

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

System.out.println("开始事务...");

// 执行目标对象的方法

Object returnValue = method.invoke(target, args);

System.out.println("提交事务...");

return returnValue;

}

}

 

 

 

5Spring注解实现AOP (简单高效)

5.1pom引入依赖

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>

5.2创建个controller

 

5.3创建一个aspect切面类

 

 

启动aspl项目并测试  分析整个执行过程

 

 

posted @ 2020-09-07 19:01  春意了无痕  阅读(138)  评论(0)    收藏  举报