Java 动态代理(ssm笔记)

个人理解

本质就是在使用真实对象之前之后做一些处理,代理的对象把真实对象存为内部属性,而外部使用代理对象执行方法代替真实对象真实的的方法。 对于外部其实就是使用真实对象一样。这样就存在两个条件: 1. 代理对象要有真实对象类型的属性(代理对象和真实对象建立代理关系) 2. 代理类要有和真实对象一样的方法签名(实现代理对象的代理逻辑方法)

实现

基于Java的jdk中提供的方式实现(在java.lang.reflect.*包),他必须需要借助一个接口才能产生一个代理对象。

条件:

  1. 接口
  2. 实现类
  3. 代理类

接口:

/**
 * 代理对象的接口
 *
 * @author whq
 */
public interface HelloWord {

    /**
     * 代理对象和真实对象共有的方法
     */
    void sayHelloWorld();
}

真实实现类:

public class HelloWorldImpl implements HelloWord {

  @Override
  public void sayHelloWorld() {
    System.out.println("Hello world, it's " + new Date());
  }
}

代理类:

/**
 * 代理逻辑类必须实现 {@link InvocationHandler}接口
 *
 * @author whq
 */
public class JdkProxyExample implements InvocationHandler {

  /** 用来保存真实对象 */
  private Object target = null;

  /**
   * 建立代理对象和真实对象的代理关系,并返回代理对象
   *
   * @param target 真实对象
   * @return 代理对象呢
   */
  public Object bind(Object target) {
    this.target = target;
    // 使用系统代理创建代理对象
    return Proxy.newProxyInstance(
      // 第一个参数是类加载器,第二个参数是把生成的代理对象挂载在那些接口下,第三个参数是定义实现方法逻辑的代理类对象
        target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  }

  /**
   * 用来代理真实对象的方法,这里是使用放射的方式,会被底层调用
   *
   * @param proxy 代理对象
   * @param method 调用真实对象的方法
   * @param args 调用真实对象的方法所传递的参数
   * @return 代理真实对象后的对象
   * @throws Throwable 异常
   */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("进入代理逻辑方法");
    System.out.println("在调度真实对象之前的服务");
    // 调用真实对象的方法
    final Object obj = method.invoke(target, args);
    System.out.println("在调度真实对象之后的服务");
    return obj;
  }
}

测试:

  @Test
  public void proxy() {
    JdkProxyExample proxy = new JdkProxyExample();
    final HelloWord bind = (HelloWord) proxy.bind(new HelloWorldImpl());
    // 代理对象调用方法,对于外部就像是真实对象调用方法一样
    bind.sayHelloWorld();
  }

CGLIB实现:解决不能使用接口的情况,只需要一个非抽象类

真实对象类:

public class ReflectServiceImpl {
  public void sayHello(String name) {
    System.out.println("Hello " + name);
  }
}

代理类:

public class CglibProxyExample implements MethodInterceptor {

  /**
   * 生成CGLIB代理对象
   *
   * @param cls 要增强的类
   * @return 代理对象
   */
  public Object getProxy(Class cls) {
    // CGLIB enhancer 增强类队形
    final Enhancer enhancer = new Enhancer();
    // 设置增强类型
    enhancer.setSuperclass(cls);
    // 定义代理逻辑对象设置为当前对象,要求当前对象实现MethodInterceptor方法
    enhancer.setCallback(this);
    // 生成并且返回代理对象
    return enhancer.create();
  }

  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
      throws Throwable {
    System.err.println("调用真实对象前");

    // CGLIB反射调用真实对象的方法
    final Object result = methodProxy.invokeSuper(o, objects);
    System.err.println("真实对象调用后");
    return result;
  }
}

测试类:

    @Test
    public void cgLib(){
        CglibProxyExample cglibProxyExample = new CglibProxyExample();
        // 得到增强后的ReflectServiceImpl对象
        final ReflectServiceImpl proxy = (ReflectServiceImpl) cglibProxyExample
          .getProxy(ReflectServiceImpl.class);

        proxy.sayHello("小明");
    }

注意:我在多次运行这个例子是发现真实函数执行和代理后置处理顺序存在随机的可能,这点有待深入了解

»