文档章节

代理模式,JDK/Cglib动态代理

丛林迷雾
 丛林迷雾
发布于 2017/05/14 15:14
字数 892
阅读 57
收藏 2

概念

  • 代理(proxy)模式:为其他对象提供一种代理,以控制对这个对象的访问。从字面上理解就是代替别人(接口)做某件事;
  • 为什么需要代理模式? 当某些接口需要部分调用者,在调用前后处理额外操作时(如:操作权限、事务等)代理模式是一种扩展能力非常强的,使用灵活的方式。
  • 理解了代理模式,那么动态代理就不难理解了,所谓动态代理就是代理对象,可以通过调用者提供的参数,动态选择被代理对象。这种设计模式在AOP、RPC等应用中是必须的。

UML

输入图片说明 如图中所示,Client可以直接调用RealSubject,也可以通过Proxy调用RealSubject,并且我们可以在Proxy中增加一些RealSubiject之外的操作,如访问权限等。

普通代理模式实现

在这里我们通过模拟文章保存后put到缓存,首先定义两个接口一个用来保存文章,一个来保存缓存、通过代理模式将其组合起来。这样做的好处是,我们可以选择用或不用缓存

  • 文章实体
public class Article{
    private Long id;
	private String title;
	private String content;

        // getters/setters略
}
  • 接口定义、实现
// 文章新增
public interface ArticleService {
      
	String add(Article article);
}

public class ArticleServiceImpl  implements ArticleService{

    @Override
	public String add(Article article){
        System.out.println("保存文章" + article.getTitle());
     }
}

// 缓存接口
public interface CacheService {

	void put(Object obj);
}

public class CacheServiceImpl implements CacheService {

    @Override
	public void put(Object obj){
        System.out.println("保存文章到缓存");
    }
}
  • 代理类实现
public class ArticleProxy implements ArticleService{

	private CacheService cache;
    private ArticleService articleService;

    public ArticleProxy(ArticleService articleService, CacheService cache){
		this.articleService = articleService;
		this.cache= cache;
	}

	@Override
	public String save(Article article){
		super.save(article);
		cache.put(article);
	}

    public static void main(String[] args) {
		ArticleService articleService = new ArticleProxy(new ArticleServiceImpl(), new CacheServiceImpl());
        Article article = new Article();
		article.setTitle("hello proxy");
		articleService.save(article);
	}
}

JDK动态代理实现

Java动态代理需要实现java.lang.reflect.InvocationHandler接口来完成缓存,然后通过java.lang.reflect.Proxy.newProxyInstance(loader, interfaces, h)把被代理对象来完成,具体实现如下:

//改写ArticleProxy
public class ArticleProxy implements InvocationHandler{

	private CacheService cache;

    private Object targert;
	
	public ArticleProxy(CacheService cache, Object targert){
		this.cache = cache;
        this.targert = targert;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj = method.invoke(targert, args);
		cache.put(obj);
		return null;
	}
	
    //main方法调用
	public static void main(String[] args) {
		ArticleService articleService = (ArticleService) Proxy.newProxyInstance(ArticleService.class.getClassLoader(), 
				new Class[]{ArticleService.class}, new ArticleProxy(new CacheServiceImpl(), new ArticleServiceImpl()));
		articleService.save();
	}
}

通过上面代码修改,我们可以发现 ArticleProxy 不仅仅可以处理文章缓存,其他类型实体也一样可以使用,这就是我们为什么要使用动态代理了。

Cglib动态代理

JDK动态代理,有一个限制,只能支持interface的代理,不支持class代理,要打破这个限制就需要使用到Cglib框架,下面通过代码演示Cglib。

// 修改ArticleServiceImpl类,去除ArticleService接口
public class ArticleServiceImpl{

	public String add(Article article){
        System.out.println("保存文章" + article.getTitle());
     }
}

// 修改ArticleProxy 类,实现InvocationHandler接口
public class ArticleProxy implements InvocationHandler{

	private CacheService cache;
    private Object targert;
	
	public ArticleProxy(CacheService cache, Object targert){
		this.cache = cache;
        this.targert = targert;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj = method.invoke(targert, args);
		cache.put(obj);
		return null;
	}
	
	public static void main(String[] args) {
		ArticleService articleService = (ArticleService) Proxy.newProxyInstance(ArticleService.class.getClassLoader(), 
				new ArticleServiceImpl().getClass().getInterfaces(), new ArticleProxy(new CacheServiceImpl(), new ArticleServiceImpl()));
		articleService.save();
	}
}

Cglib下载地址:http://central.maven.org/maven2/cglib/cglib/2.2.2/cglib-2.2.2.jar

// maven :
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

总结

  1. 通过实现InvocationHandler接口创建调用处理器
  2. 通过Proxy.newProxyInstance(loader, interfaces, h)为指定的接口创建代理
  3. 上面我们所使用的是JDK动态代理,JDK代理机制只支持interface的代理,并不支持单纯class的代理;如果要实现class代理可以选择cglib来实现

© 著作权归作者所有

下一篇: 数据结构-队列
丛林迷雾
粉丝 8
博文 24
码字总数 8093
作品 0
杭州
高级程序员
私信 提问
JDK动态代理和Cglib的动态代理

最简单的是静态代理方法,即代理模式,这里就不多啰嗦了。。 重点说一下JDK的动态代理和Cglib的动态代理吧 先说JDK的,需要被代理的类需要有接口,否则无法实现 package proxy.dynamic; pub...

Eviltuzki
2015/10/29
0
0
Spring AOP是什么?你都拿它做什么?

原文出处:我叫刘半仙 为什么会有面向切面编程(AOP)?我们知道Java是一个面向对象(OOP)的语言,但它有一些弊端,比如当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日志、...

我叫刘半仙
01/12
0
0
详解 Java 中的三种代理模式

代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这...

Java小铺
2018/08/23
0
0
Java设计模式综合运用(动态代理+Spring AOP)

AOP设计模式通常运用在日志,校验等业务场景,本文将简单介绍基于Spring的AOP代理模式的运用。 1. 代理模式 1.1 概念 代理(Proxy)是一种提供了对目标对象另外的访问方式,即通过代理对象访问...

landy8530
2018/10/05
0
0
代理模式【Proxy】 AOP

使用场景:代理类更好的控制被代理类事前、事后工作。例如在所有被代理类加上执行时间的记录。 类似SPRING AOP 日志和事务的横切 介绍了 静态代理 动态代理 jdk cglib的原理和优缺点 jdk cg...

吹比龙
2017/03/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring系列教程八: Spring实现事务的两种方式

一、 Spring事务概念: 事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。...

我叫小糖主
今天
5
0
CentOS 的基本使用

1. 使用 sudo 命令, 可以以 root 身份执行命令, 必须要在 /etc/sudoers 中定义普通用户 2. 设置 阿里云 yum 镜像, 参考 https://opsx.alibaba.com/mirror # 备份mv /etc/yum.repos.d/CentO...

北漂的我
昨天
3
0
Proxmox VE技巧 移除PVE “没有有效订阅” 的弹窗提示

登陆的时候提示没有有效的订阅You do not have a valid subscription for this server. Please visit www.proxmox.com to get a list of available options. 用的是免费版的,所以每次都提示......

以谁为师
昨天
3
0
Java设计模式之外观模式(门面模式)

什么是外观模式   外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口...

须臾之余
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部