动态代理模式

2405 查看

描述:代理对象和被代理对象具有相同的行为,客户端通过代理对象实现对被代理对象调用,代理对象除了可以代理被代理对象的所有行为外,还可以在被代理对象的所有行为上添加一些额外的内容,如开闭事务,权限拦截等;动态代理可以生成一个不用实现被代理类所有接口的代理类,它内部通过被代理类的classLoader和反射机制实现被代理类的所有接口。。

场景:在数据库操作中,假如所有增删改查操作都需要加log记录,可以代理这个数据库操作,然后在运行这些增删改查操作时加一个log记录,客户端使用方式仍然不变。

实现:

数据库操作:

interface Dao {
    void insert();
    void delete();
}

关于人员的数据库操作:

class UserDao implements Dao {
    @Override
    public void insert() {
        System.out.println("insert user instance to db!");
    }
    @Override
    public void delete() {
        System.out.println("delete user instance from db!");
    }
}

定义一个代理类代理UserDao,如果使用静态代理,那么这个类必须实现Dao接口,这里采用动态代理类,免去实现代理类定义的所有接口。

class UserDaoProxy implements InvocationHandler {
    Dao dao;
    UserDaoProxy(Dao dao) {
        this.dao = dao;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(dao, args);
        after();
        return result;
    }
    private void before() {
        System.out.println("开始log...");
    }
    private void after() {
        System.out.println("结束log");
    }
}

客户端调用:

public class ProxyDemo {
    public static void main(String[] args) {
        UserDaoProxy proxy = new UserDaoProxy(new UserDao());
        Dao dao = (Dao)Proxy.newProxyInstance(UserDao.class.getClassLoader(), UserDao.class.getInterfaces(), proxy);
        dao.insert();
        dao.delete();
    }
}

打印结果:

开始log...
insert user instance to db!
结束log
开始log...
delete user instance from db!
结束log

结论:通过代理类即能保持原接口调用不变,还能对接口调用的前后增加额外的业务代码,甚至可以改变接口的实现,why?想想现实中的代理就知道了。