·前缘
第一次接触代理模式是在学习《大话设计模式》这本书的时候,代理顾名思义就是创建一个代理类来实现对目标对象的访问控制。提供这个代理类的好处就是可以在实现目标对象功能的前提下,自定义实现方式(比如增加额外的功能操作)可以扩展目标对象的功能。下面先用一张图来说明一下我的思路:
上图中Interface是公共的接口,Proxy是代理类,它实现抽象接口并依赖于目标对象。RealObject也实现了抽象接口。代理模式的关键点在于代理对象与目标对象。代理对象是对目标对象的扩展,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。它主要体现了设计模式的开闭原则:对扩展开发,对修改关闭。怎么理解呢?很简单,我们可以借助代理类来增加一些功能,而不需要修改原有的代码。
·分类
根据具体实现方式的不同代理模式按照代理的创建时期可以分为动态代理和静态代理。
静态代理:
由程序员创建或特定工具自动生成源码,再对其进行编译。在程序运行前,代理类的.class文件就已经存在。
动态代理:
在程序运行时,通过反射机制动态创建出来。
·静态代理实例
实现静态代理主要有三步:
1、定义业务接口、业务接口实现类
/**
* 定义一个业务接口
* @author guigui
*
*/
public interface Account {
//查询
public void queryAccount();
//修改
public void updateAccount();
}
/**
* 目标类(委托类)
* @author guigui
*
*/
public class AccountImpl implements Account{
@Override
public void queryAccount() {
System.out.println("--查询方法--");
}
@Override
public void updateAccount() {
System.out.println("--修改方法--");
}
}
2、定义代理类,且实现业务接口;
/**
* 代理类
* @author guigui
*
*/
public class AccountProxy implements Account{
private AccountImpl accountImpl;
public AccountProxy(AccountImpl accountImpl){
this.accountImpl=accountImpl;
}
@Override
public void queryAccount() {
System.out.println("---查询前---");
accountImpl.queryAccount();
System.out.println("---查询后---");
}
@Override
public void updateAccount() {
System.out.println("---更新前---");
accountImpl.updateAccount();
System.out.println("---更新后---");
}
}
3、客户端调用。
/**
* 实例化一个调用代理类的客户端
* @author guigui
*
*/
public class TestProxy {
public static void main(String[] args) {
AccountImpl accountImpl=new AccountImpl();
AccountProxy accountProxy=new AccountProxy(accountImpl);
accountProxy.queryAccount();
accountProxy.updateAccount();
}
}
至此,实现了静态代理。虽然它做到了在不修改目标对象的功能的前提下,对目标代码进行扩展。但是不难发现,代理对象需要与目标对象实现一样的接口,所以会有很多代理类,还有就是接口方法有修改,目标对象与代理对象都需要维护。
·动态代理实例
动态代理与静态代理的区别在于动态代理不需要实现接口。动态代理类的字节码在程序运行时由java的反射机制动态生成。代理对象的生成是利用JDK的API或者Cglib代理。
··使用JDK的动态代理,使用动态代理的对象必须实现一个或多个接口。
1、代理工厂类(实现InvocationHandler接口)
/**
* 创建动态代理对象
* 动态代理不需要实现接口,但是要指定接口类型
* @author guigui
*
*/
public class ProxyFactory implements InvocationHandler{
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target
* @return
*/
public Object GetInstance(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("before");
//执行方法
result=method.invoke(target, args);
System.out.println("after");
return result;
}
}
2、客户端调用(传入真正的委托类)
/**
* 测试jdk动态代理类
* @author guigui
*
*/
public class JDKProxyTest {
public static void main(String[] args) {
ProxyFactory proxy = new ProxyFactory();
// 在这里进行真正的对象传入
Account account=(Account)proxy.GetInstance(new AccountImpl());
account.queryAccount();
}
}
··使用Cglib动态代理,它是在内存中创建一个子类对象从而实现对目标对象功能的扩展。
1、创建ProxyFactory代理类
/**
* cglib子类代理工厂
* 对AccountImpl在内存中动态创建一个子类对象
* @author guigui
*
*/
public class ProxyFactory implements MethodInterceptor{
//维护目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开始事务...");
//执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务...");
return returnValue;
}
2、客户端测试类
/**
* cglib代理测试类
* @author guigui
*
*/
public class CglibProxyTest {
public static void main(String[] args) {
//目标对象
AccountImpl target=new AccountImpl();
//代理对象
AccountImpl proxy=(AccountImpl)new ProxyFactory(target).getProxyInstance();
proxy.queryAccount();
}
}