静态代理:
有一个接口:
public interface UserManager { public void addUser(User user); public void updateUser(User user); public void deleteUser(User user); }
我们来实现它:
public class UserManagerImpl implements UserManager { @Override public void addUser(User user) { System.out.println("UserManagerImpl.addUser"); } @Override public void updateUser(User user) { System.out.println("UserManagerImpl.updateUser"); } @Override public void deleteUser(User user) { System.out.println("UserManagerImpl.deleteUser"); } }
现在我们要在方法内部增加log和捕获异常:
public class UserManagerImpl implements UserManager { @Override public void addUser(User user) { System.out.println("log:start-->addUser" + user); try { System.out.println("UserManagerImpl.addUser"); System.out.println("log:success-->addUser"); } catch(RuntimeException e) { System.out.println("log:error-->addUser"); throw new RuntimeException(e); } } @Override public void updateUser(User user) { System.out.println("UserManagerImpl.updateUser"); } @Override public void deleteUser(User user) { System.out.println("UserManagerImpl.deleteUser"); } }
但是我们提供的方法是用来执行业务的,而不是进行输出log、捕获异常的。在这里做这些工作违背了这接口的功能,所以我们创建代理来做这些工作:
public class UserManagerImplProxy implements UserManager { private UserManager userManager; public UserManagerImplProxy(UserManager userManager) { this.userManager = userManager; } @Override public void addUser(User user) { System.out.println("log:start-->addUser" + user); try { userManager.addUser(user); System.out.println("log:success-->addUser"); } catch(RuntimeException e) { System.out.println("log:error-->addUser"); throw new RuntimeException(e); } } @Override public void updateUser(User user) { } @Override public void deleteUser(User user) { } }
我们创建了这样一个代理类。在它里面我们输出log、捕获异常,不会对业务代码进行污染了。但是还有问题,在addUser()中的代码还会出现在updateUser()和deleteUser()中,出现了重复的代码。现在我们来看看动态代理是怎么解决这一问题的。
动态代理:
动态代理的代理类是在运行期生成出来的。
public class LogHandler implements InvocationHandler { private Object targetObj; public Object newProxy(Object targetObj) { this.targetObj = targetObj; return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("log:start-->" + method.getName()); for(Object arg : args) { System.out.println("log:params-->" + arg); } Object result = null; try { result = method.invoke(targetObj, args); System.out.println("log:success-->" + method.getName()); }catch(RuntimeException e) { System.out.println("log:error-->" + method.getName()); throw e; } return result; } }
我们不必为目标对象的每个方法都输出log。我们用newProxy()方法生成动态代理对象,并将目标对象targetObj委托给动态代理。当执行目标对象中的方法时,会调用到动态代理对象的invoke()方法(我们在用Proxy.newProxyInstance()方法创建动态代理对象时,将this传给了该对象,所以该对象中有了invoke()方法)。该方法中含有目标对象方法的方法对象method以及参数列表args,这样在动态代理对象的invoke()方法中,我们又可以来执行目标对象的方法,并可以在该方法中执行想要的操作。实现如下:
LogHandler handler = new LogHandler(); UserManager userManager = (UserManager)handler.newProxy(new UserManagerImpl()); userManager.addUser(new User(1, "zy"));