Proxy(代理)模式是通过创建一个代理对象,用这个代理对象代替真实对象,客户端得到这个代理对象后,操作这个代理对象时,实际上功能还是由真实对象来完成。代理对象夹在客户端和真实对象之间,相当于一个中转,中转的时候可以添加自己的业务逻辑。
示类代码:
1、Account接口:
- /**
- * 账户接口
- */
- public interface Account {
- public void updateAccount();
- public void queryAccount();
- }
2、实现类:
- public class AccountImpl implements Account {
- @Override
- public void updateAccount() {
- System.out.println("更新账户...");
- }
- @Override
- public void queryAccount() {
- System.out.println("查询账户...");
- }
- }
3、代理对象:
- public class AccountProxy implements Account {
- private AccountImpl account;
- public AccountProxy(AccountImpl account) {
- this.account = account;
- }
- @Override
- public void updateAccount() {
- System.out.println("处理之前...");
- account.updateAccount();
- System.out.println("处理之后...");
- }
- @Override
- public void queryAccount() {
- System.out.println("处理之前...");
- account.queryAccount();
- System.out.println("处理之后...");
- }
- }
上面实现的代理方式称为静态代理。通过观察代码发现,如果目标接口发生变化,那么代理类和具体的目标实现类都要发生变化,不灵活。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,此时就可使用Java内建的动态代理来完成。
静态代理实现的时候,若在目标接口中定义很多方法,代理类里也要实现很多方法,也动态代理实现的时候,虽然目标接口上定义了很多方法,但代理类只有一个invoke方法。这样,当目标接口发生变化时,动态代理的接口就不需要发生变化了。
Java的动态代理目前只能代理接口,基本的实现是依靠Java的反射机制和动态生成class的技术,来动态生成被代理的接口的实现对象,若要实现类的代理,可以使用cglib。
Java动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
参数说明:
Object proxy:被代理的对象
Method method:要调用的方法
Object[] args:方法调用时需要的参数
Proxy类:
Proxy是专门完成代理的操作类,可通过此类为一个或多个接口动态的生成实现类,此类提供了如下方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumenException
参数说明:
ClassLoader loader:定义代理类的类加载器(目标对象)
Class<?>[] interfaces:代理类要实现的接口列表
InvocationHandler h:指派方法调用的调用处理程序
上述Account接口的代理类示例代码如下:
- public class AccountProxy implements InvocationHandler {
- private Object target;
- // 绑定委托对象并返回一个代理类
- public Object bind(Object target) {
- this.target = target;
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this); //要绑定一个接口(cglib弥补了这一缺陷)
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- System.out.println("开始...");
- result = method.invoke(target, args);
- System.out.println("结束...");
- return result;
- }
- }
写一单元测试方法:
- @Test
- public void test() {
- AccountProxy accountProxy = new AccountProxy();
- Account account = (Account) accountProxy.bind(new AccountImpl());
- account.updateAccount();
- account.queryAccount();
- }