Java 代理模式

什么是代理

代理是一种设计模式,它的核心思想,是将对目标的访问转移到代理对象上。这样做的好处就是,目标对象在不改变代码的情况下,可以通过代理对象加一些额外的功能。这是一种编程思想,在不改变原有代码的情况下,通过代理增加一些扩展功能。

代理过程如图所示,用户访问代理对象,代理对象通过访问目标对象,来达到用户访问目标对象的目的,

图片

代理模式包含一下三个角色:

  • ISubject:接口对象,该接口是对象和它的代理共用的接口。

  • TargetSubject:目标对象,是实现抽象主题接口的类。

  • Proxy:代理角色,内部含有对目标对象TargetSubject的引用,从而可以操作真实对象。代理对象提供与目标对象相同的接口,以便在任何时刻都能代替目标对象。同时,代理对象可以在执行目标对象操作时,附加其他的操作,相当于对真实对象进行封装。

常见的代理模式分为静态代理和动态代理,动态代理在Java中的实现分为JDK动态代理和cglib代理。

静态代理

在之前已经说过,在代理模式中有三个角色,一是目标接口,二是目标对象,三是代理对象。

现在以具体代码来实现,首先是目标接口如下:

 public interface IBlogService {    void writeBlog();}

目标对象实现了目标接口,代码如下:

public class BlogService implements IBlogService {    @Override    public void writeBlog() {        System.out.println("i'm writing...");    }}

静态代理对象,通过构造方法获取到目标对象,并实现了目标接口,在目标接口的方法里调用了目标对象的方法,代码如下:

public class BlogStaticProxy implements IBlogService{    private IBlogService blogService;    public BlogStaticProxy(IBlogService blogService) {        this.blogService = blogService;    }    @Override    public void writeBlog() {        System.out.println("start writing...");        blogService.writeBlog();        System.out.println("end writing...");    }}

测试:

public class TestStaticProxy {    public static void main(String[] args) {        IBlogService target = new BlogService();        BlogStaticProxy proxy = new BlogStaticProxy(target);        proxy.write();    }}

start writing…

i’m writing…

end writing…

静态代理,在不修改目标对象的情况下,可以通过代理对象做额外的扩展功能。但静态方法不是很灵活,如果目标接口的代码修改,目标对象和代理对象都需要修改。

动态代理在一定程度上避免这种情况,动态代理不需要代理对象实现目标接口,并且上在java 虚拟机的内存中动态的生成代理对象

Jdk动态对象

Jdk的动态代理由Proxy这个类来生成,它有三个参数:

  • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

  • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

 public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException    {    }

Jdk的动态代理代码如下:

 public class JdkBlogProxyFactory {    private Object target;    public JdkBlogProxyFactory(Object target) {        this.target = target;    }    public Object newInstance() {        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),                (proxy, method, args) -> {                    System.out.println("start writing");                    Object o = method.invoke(target, args);                    System.out.println("end writing");                    return o;                });    }}

测试类:

public class TestJdkProxy {    public static void main(String[] args) {        IBlogService target = new BlogService();        System.out.println(target.getClass());        // 给目标对象,创建代理对象        IBlogService proxy = (IBlogService) new JdkBlogProxyFactory(target).newInstance();        // class $Proxy0   内存中动态生成的代理对象        System.out.println(proxy.getClass());        // 执行方法   【代理对象】        proxy.writeBlog();    }}

控制台打印如下:

class com.forezp.proxy.BlogServiceclass com.sun.proxy.$Proxy0start writingi'm writing...end writing

CGLib动态代理

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

CglibBlogFactory代理工厂类如下:

public class CglibBlogFactory implements MethodInterceptor {    private Object target;    public CglibBlogFactory(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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {        System.out.println("start writing...");        //执行目标对象的方法        Object returnValue = method.invoke(target, objects);        System.out.println("end writing...");        return returnValue;    }}

测试类:

public class TestCglib {    public static void main(String[] args) {        IBlogService target = new BlogService();        //代理对象        IBlogService proxy = (IBlogService) new CglibBlogFactory(target).getProxyInstance();        //执行代理对象的方法        proxy.writeBlog();    }}

运行程序,控制台打印:

start writing...i'm writing...end writing...

参考资料

http://www.cnblogs.com/cenyu/p/6289209.html

http://blog.csdn.net/yakoo5/article/details/9099133/


更多相关文章

  1. Github标星19K+Star,10分钟自建对象存储服务!
  2. golang 发送post请求 其body中json对象使用变量作为value
  3. Java 程序员应该知道的 10 个面向对象理论
  4. 一个GCRoot不可达的对象,会立刻被垃圾回收吗?
  5. Object对象你真理解了吗?
  6. HotSpot VM 中对象的内存分析
  7. 从对象生命周期的经验统计到垃圾回收算法
  8. 什么样的 Java 对象会被当垃圾回收?

随机推荐

  1. golang如何定义一个二维数组
  2. Golang如何接收前端的参数
  3. golang判断是文件还是文件夹
  4. golang底层是c语言吗?
  5. Golang如何接收输入
  6. Golang能写人工智能吗
  7. golang判断是否是素数的方法
  8. golang的组合和继承之间有什么区别?
  9. golang可以写单片机吗
  10. Golang能使用多核cpu吗