Spring框架有一个很重要的机制——代理机制,而这个机制是实现Spring一个重要编程思想——切面编程思想重要工具。
那么代理功能有什么用呢?假设我们有一个方法,我们想查看这个方法的执行性能与开销时间,我们是怎么做的呢?

可能大部分的人都会这样直接在方法内部加上这两句代码:
1 2
| long start = System.currentTimeMillis(); System.out.println("该方法消耗时间" + (System.currentTimeMillis() - start));
|
可能感觉这样子,才两行代码,没有什么大不了的,但是如果方法一多,需要对大多数的业务逻辑代码进行开销记录呢?那个就会增加无数的重复代码,而这些代码跟我们的业务逻辑是根本没有关系的,我们只是希望在这个方法执行的过程中能够记录其开销而已,并不想去破坏这个方法原有的代码结构。那么这个要怎么实现呢?这个其实就是依靠Java自带的代理机制来解决,其实Java的JDK就有类的动态代理功能,而这本质又依赖于Java中的反射机制来实现。
那么什么是代理机制呢?所谓代理,就是我把一切都弄好了,但是呢,我本身不去做这件事情,我把这件事情的实施交给别人,这就是代理机制;只不过现在是换成我们主动想要一个代理人去实施这个事情,而不是方法本身去实施;当目标方法准备执行时被我们的代理类拦截了下来,然后,由代理类自带的方法去间接执行目标方法,在这过程当中,就可以增加任何你想要做的事情:加入开销时间、记录每一时刻执行的方法的详细信息(方法名、参数名)等等;这样,你会发现,只需要一个代理类,就可以实现我们刚刚想对所有方法进行开销时间的记录操作,并且还能不断扩充我们想要实现的增强功能(附录:这个其实已经有一点点Spring的切面编程的意味了)
代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class MyInvokationHandler<E> implements InvocationHandler {
private E target;
public MyInvokationHandler(E target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Long beginTime = System.currentTimeMillis(); Object returnValue = method.invoke(target, args); System.out.println("方法" + method.getName() + "调用结束,耗时"+ (System.currentTimeMillis() -beginTime)); return returnValue; } }
|
被代理的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface proxyInterface extends ControlDatabase {
@Override <T>ResultBean<T> query(Object o, String sql) throws SQLException;
@Override <T>ResultBean<T> insert(PreparedStatement preparedStatement) throws SQLException;
@Override <T>ResultBean<T> delete(PreparedStatement preparedStatement);
@Override <T>ResultBean<T> update(PreparedStatement preparedStatement); }
|
实现代理调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class MyProxy{
private ControlDatabase controlDatabase; private InvocationHandler handler; private proxyInterface proxy;
public MyProxy(ControlDatabase controlDatabase) { this.controlDatabase = controlDatabase; handler = new MyInvokationHandler<>(controlDatabase); proxy = (proxyInterface) Proxy.newProxyInstance(proxyInterface.class.getClassLoader(), new Class[]{proxyInterface.class}, handler); }
public proxyInterface getProxy() { return proxy; } }
public class messageImpl implements messageMap { @Override public <T> ResultBean<T> queryCompyInfo() throws SQLException { proxyInterface proxy = new AdaperFactory(new MysqlQuery()).getProxy(); Connection connection = proxy.getConnection(); String sql = "SELECT * FROM Lanmu WHERE Lname='公司介绍'"; Statement statement = connection.createStatement(); return new ResultBean(proxy.query(statement, sql).getData()); }
|
从实现代理调用的 MyProxy 这个类中我们可以看出,只要是继承了proxyInterface这个接口的类或者接口,都会被我们的代理类所拦截下来,进入代理的流程。让我们通过一个视频来了解下吧:
YouTube站点
[youtube https://www.youtube.com/watch?v=WVU7S8nD9NQ&w=560&h=315]
哔哩哔哩站点
https://www.bilibili.com/video/av18146765/