动态代理

释放双眼,带上耳机,听听看~!

在上一篇中我们已经介绍了AOP相关的知识,并且了解了spring是通过动态代理的方式实现AOP逻辑的。在spring中动态代理也分为两种一种是JDK动态代理,一种是CGLib动态代理。下面我们看一下这两种动态代理的区别。我们首先看一下在没有动态代理时,添加事物的的逻辑处理,也就上一篇中的事例。

public interface IUserService {

  public void login(String username, String password);

  public void register(String username, String nickName, String password);
}
public class UserServiceImpl implements IUserService {

  public void login(String username, String password) {
    TransactionManager.beginTransaction();
    System.out.println(String.format("用户登陆: username: %s password: %s", username, password));
    TransactionManager.commit();
  }

  public void register(String username, String nickName, String password) {
    TransactionManager.beginTransaction();
    System.out.println(String.format("用户注册: username: %s nickName: %s password: %s", username, nickName, password));
    TransactionManager.commit();
  }

}
public class TransactionManager {
  public static void beginTransaction() {
    System.out.println("开启事物");
  }
  public static void commit() {
    System.out.println("提交事物");
  }
}
@Test
public void test() {
  IUserService userService = new UserServiceImpl();
  userService.login("admin","jilinwula");
  userService.register("admin","吉林乌拉","jilinwula");
}
开启事物
用户登陆: username: admin password: jilinwula
提交事物
开启事物
用户注册: username: admin nickName: 吉林乌拉 password: jilinwula
提交事物

虽然上述代码已经实现了我们的逻辑,但是在上一篇中我们已经介绍过了,上述代码的问题就是会有重复的有关事物的代码添加到业务类中,这样很不方便维护。解决的办法就是通过AOP方式来解决,下面我们分别采用JDK动态代理和CGLib动态代理技术来解决上述问题。

  • JDK动态代理
public interface IUserService {

  public void login(String username, String password);

  public void register(String username, String nickName, String password);
}
public class UserServiceImpl implements IUserService {

  public void login(String username, String password) {
    System.out.println(String.format("用户登陆: username: %s password: %s", username, password));
  }

  public void register(String username, String nickName, String password) {
    System.out.println(String.format("用户注册: username: %s nickName: %s password: %s", username, nickName, password));
  }

}
public class PerformanceHandler implements InvocationHandler {

  private Object target;

  public PerformanceHandler(Object target) {
    this.target = target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("JDK动态代理");
    TransactionManager.beginTransaction();
    Object object = method.invoke(target, args);
    TransactionManager.commit();
    return object;
  }
}
@Test
public void test() {
  IUserService target = new UserServiceImpl();
  PerformanceHandler handler = new PerformanceHandler(target);
  IUserService userService = (IUserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
  userService.login("admin","jilinwula");
  userService.register("admin","吉林乌拉","jilinwula");
}
JDK动态代理
开启事物
用户登陆: username: admin password: jilinwula
提交事物
JDK动态代理
开启事物
用户注册: username: admin nickName: 吉林乌拉 password: jilinwula
提交事物

上述代码就是采用JDK动态代理技术实现AOP功能的,通过上述代码实现AOP功能虽然比较简单,但是有一个弊端就是JDK代理只能支持接口类型,也就是只能为接口提供动态代理功能,而CGLib动态代理则可以直接为类创建代理类。下面我们通过CGLib动态代理实现上述功能。

  • CGLib动态代理
public class CglibProxy implements MethodInterceptor {

  private Enhancer enhancer = new Enhancer();

  public Object getProxy(Class clazz) {
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);
    return enhancer.create();
  }

  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("CGLib动态代理");
    TransactionManager.beginTransaction();
    Object object = methodProxy.invokeSuper(o, objects);
    TransactionManager.commit();
    return object;
  }
}
@Test
public void test() {
  CglibProxy proxy = new CglibProxy();
  IUserService userService = (IUserService) proxy.getProxy(UserServiceImpl.class);
  userService.login("admin","jilinwula");
  userService.register("admin","吉林乌拉","jilinwula");
}
CGLib动态代理
开启事物
用户登陆: username: admin password: jilinwula
提交事物
CGLib动态代理
开启事物
用户注册: username: admin nickName: 吉林乌拉 password: jilinwula
提交事物
  • JDK动态代理与CGLib动态代理的区别
  1. JDK动态代理只能为接口创建代理类,而CGLib动态代理而可以直接为类创建代理类。
  2. JDK动态代理创建代理类的速度要比CGLib动态代理创建代理类的速度要快。
  3. CGLib动态代理创建代理类的性能要比JDK动态代理创建代理类的性能要高。

所以在为单例对象创建代理类时,因为不需要频繁的创建代理对象,所以优先考虑用CGLib动态代理来创建,这样该代理类的执行时的性能比较高,反之则采用JDK动态代理创建代理类。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧