您的位置:首页 > 编程语言 > Java开发

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

2016-10-22 20:56 302 查看

代理的简介

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"/>)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息