Java常用GoF设计模式之一代理模式

本文详细介绍了代理模式的概念及其在软件开发中的应用。包括静态代理、基于JDK接口的动态代理及基于CGLIB类的动态代理的实现原理和优缺点。

代理的简介

1、代理模式的概念

所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。
2、代理模式的作用是:
为其他对象提供一种代理以控制对这个对象的访问。
3、代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口; 
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。 

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

代理分为静态代理和动态代理;而动态代理又分为Java基于接口的动态代理和cglib基于类的动态代理。

静态代理的实现

抽象角色可以是接口或抽象类

package cn.gof.proxy.dynamicproxy;
/**
 *author:zhapan
 *date:	2016年10月22日
 *
 */
public interface Singer {

	void singing();
	void dancing();
}

代理对象:

package cn.gof.proxy.staticproxy;
/**
 *author:zhaopan
 *date:	2016年10月22日
 *歌手经济人
 */
public class SingerAngent extends Singer{

	private Singer singer;
	
	public SingerAngent(Singer singer){
		this.singer=singer;
	}

	@Override
	public void singing() {
		// TODO Auto-generated method stub
		System.out.println("抽成");
		singer.singing();
		System.out.println("给你");
	}

	@Override
	public void dancing() {
		// TODO Auto-generated method stub
		System.out.println("抽成");
		singer.dancing();
		System.out.println("给你");
	}
}
真实角色:

package cn.gof.proxy.staticproxy;
/**
 *author:zhaopan
 *date:	2016年10月22日
 *王菲
 */
public class WangFei extends Singer {

	@Override
	void singing() {
		// TODO Auto-generated method stub
		System.out.println("你在终点等我?");
	}

	@Override
	void dancing() {
		// TODO Auto-generated method stub
		System.out.println("会跳吗?");
	}

}

package cn.gof.proxy.staticproxy;
/**
 *author:zhaopan
 *date:	2016年10月22日
 *迈克杰克逊
 */
public class JackSon extends Singer{

	@Override
	void singing() {
		// TODO Auto-generated method stub
		System.out.println("we are the world");
	}

	@Override
	void dancing() {
		// TODO Auto-generated method stub
		System.out.println("太空舞步");
	}

}

原理:
对普通一个接口与一直实现类在加入一个代理类,用于包装实现类中实现的方法,而业务使用方只需要实例化代理类,并传递需要代理的普通类即可。
优点:
编译时生成代码,性能高
缺点:
一个代理类只能为一个接口服务,开发中必然会产生过多的代理
所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码

基于JDK的接口动态代理

接口和真是角色代码不变,只是改变代理角色的代码:

package cn.gof.proxy.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 *author:zhaopan
 *date:	2016年10月22日
 *歌手经济人
 */
public class SingerAngentHandler implements InvocationHandler{

	private Singer singer;
	
	public SingerAngentHandler(Singer singer){
		this.singer=singer;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("抽成");
		method.invoke(singer, args);
		System.out.println("给你");
		return null;
	}

	
}


基于cglib的类的动态代理

接口和真是角色代码不变,只是改变代理角色的代码:

package cn.gof.proxy.dynamicproxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 *author:zhaopan
 *date:	2016年10月22日
 *
 */
public class SingerAngentCglib implements MethodInterceptor{

	public Object getInstance(Class clazz){
		Enhancer enhancer=new Enhancer();
		enhancer.setSuperclass(clazz);
		enhancer.setCallback(this);
		return enhancer.create();
	}
	
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("抽成");
		Object object = proxy.invokeSuper(obj, args);
		System.out.println("给你");
		return object;
	}

}
原理:
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
优点:
可以通过一个代理类,完成所有代理工作,不需要向静态代理需要一个一个实现接口来代理
缺点:
通过反射动态代理方法将消耗系统性能,如果非常多的话,性能比较低

JDK动态代理和CGLIB字节码生成的区别? 
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 ;CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。因为是继承,所以该类或方法不要声明成final。

动态代理在我们使用的框架Spring中已经运用到,主要是AOP,他主要是动态代理+反射的方式。如Spring通过CGLib来实现了类代理方式,通过Java动态代理来实现接口代理,从而把两种动态代理结合使用

JDK动态代理和CGLib动态代理都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是AspectJ,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为JDK动态代理和CGLib动态代理每次运行都需要增强。
Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值