标签:png tor 不能 计算 mep author 定义 load public
为某个对象(目标对象)提供一种代理对象以控制对这个对象的访问。在某些情况下在(比如安全性问题),客户端不能直接访问某个对象(目标对象),还是通过代理对象间接访问目标对象,代理对象在客户端和目标对象之间起到中介的作用,而且可以通过代理对象对目标对象的功能进行扩展,代理对象一般对目标对象的非核心业务的扩展,比如权限控制问题,记录日志,事务控制等等。我们日常的生活的代理模式例子有房产中介,明星经纪人,火车票代售点等等,在工作中代理模式有windows快捷键,spring框架aop等等
代码如下:
1:创建一个接口Movable接口(抽象类也行)
/**
* 该接口用来指定代理的方法(需要增加内容的方法),代理对象,被代理对象都该继承该接口 * @author Administrator * */ public interface Movable { public void move() throws InterruptedException; }
2:创建目标类Plane,实现Movable接口
/** * 需要代理的对象飞机类,实现movable接口 * @author Administrator * */ public class Plane implements Movable { public void move() throws InterruptedException { System.out.println("plane luanching..."); Thread.sleep(new Random().nextInt((int) (1000))); } }
3.1:创建一个时间代理类PlaneTimeProxy,实现movable接口,并持有一个Movable类型的引用。
/** * 飞机类的时间代理对象,用来计算飞机飞行的时间,即是飞机对象move方法调用的时间。 * @author Administrator * */ public class PlaneTimeProxy implements Movable{ Movable mover; public PlaneTimeProxy(Movable mover){ this.mover=mover; } public void move() throws InterruptedException { // TODO Auto-generated method stub long begin=System.currentTimeMillis(); mover.move(); long end =System.currentTimeMillis(); System.out.println("plane time:"+(end-begin)); } }
飞机飞行记录代理类PlaneLogProxy(日志)实现movable接口,并持有一个Movable类型的引用。
/** * 飞机飞行过程记录代理类(日志) * @author Administrator * */ public class PlaneLogProxy implements Movable { Movable mover; public PlaneLogProxy(Movable mover){ this.mover=mover; } public void move() throws InterruptedException { System.out.println("plane begin"); mover.move(); System.out.println("plane end"); } }
4:客户端测试类
/** *静态代理测试类 */ public class TestProxy { public static void main(String[] args) throws InterruptedException { Movable p=new Plane(); //日志代理类 PlaneLogProxy plp=new PlaneLogProxy(p); plp.move(); //时间代理类型 PlaneTimeProxy simplePtp =new PlaneTimeProxy(p); simplePtp.move(); //时间代理类嵌套日志代理类 PlaneTimeProxy ptp=new PlaneTimeProxy(plp); ptp.move(); } }
静态代理总结:使用静态代理对目标对象功能的扩展,比继承更加灵活,比如上面的例子,如果即需要记录飞机时间,记录飞行的日志,就需要再在新建一个类实现Movable接口,如果用静态代理则可以通过嵌套方式实现。静态代理的不足,1:如果一个目标类被多个类代理,则需要创建多个代理类,而且代理类的逻辑相似,重复代码写了多遍,2:如果在接口增加一个方法,则需要修改代理类跟目标类的逻辑,为了解决上面的问题就产生了动态代理了,动态代理有二种,一种是jdk代理,一种是cglib代理。
还是以上面的列子的日志代理类为例,接口跟目标类已经有了,就不再在下面展示了,代码如下:
创建一个类实现InvocationHandler接口,该类持有一个Movable类型的引用,目标对象的功能扩展通过重写invoke方法实现:
public class MyHandler implements InvocationHandler{ Movable mover; public MyHandler(Movable mover) { super(); this.mover = mover; } /** * * @param proxy 第一个参数指的是jdk生成的代理对象 * @param method 第二个参数指的是目标对象的目标方法 * @param args 第三个参数指的是目标对象的目标方法的参数 * @return 方法返回值为调用目标方法的返回值 * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("plane begin");//新增的逻辑 Object obj=method.invoke(mover, args);//调用目标对象的目标方法 System.out.println("plane end");//新增的逻辑 return obj; } }
客户端测试类:
/** * jdk动态代理:用反射技术,由jdk动态在内存生成代理对象。 * @author Administrator * */ public class TestJdkProxy { public static void main(String[] args) throws InterruptedException { Movable p= (Movable) new Plane(); MyHandler h=new MyHandler(p); /** *通过Proxy类的newProxyInstance方法创建代理对象,newProxyInstance方法:第一个参数表示目标类的类加载器, * 第二个参数指定目标类实现的接口的字节码数组对象, * 第三个参数指的是实现目标方法扩展的InvocationHandler实现类。 */ Movable mover=(Movable) Proxy.newProxyInstance(Plane.class.getClassLoader(), new Class[]{Movable.class}, h); mover.move(); } }
jdk代理总结:用反射技术,由jdk动态在内存生成代理对象,不需要自己创建代理类,生成代理对象,解决了静态代理的不足。但是现在目标类没有实现接口,想对目标类功能进行扩展,这时就需要用cglib代理实现。
还是以上面的列子的日志代理类为例,接口跟目标类已经有了,就不再在下面展示了,代码如下:
创建一个拦截器类实现MethodInterceptor接口,持有一个Movable类型的引用,通过重写intercept方法来实现目标类功能的增强。
public class MyInterceptor implements MethodInterceptor{ Movable mover; public MyInterceptor(Movable mover) { this.mover = mover; } @Override public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable { System.out.println("plane begin"); //Object obj=methodProxy.invoke(mover, arg2); Object obj=methodProxy.invokeSuper(proxy,arg2); System.out.println("plane end"); return obj; } }
客户端测试类:
/** * cglib代理是叫子类代理,通过在内存构建一个子类,从而实现目标对象功能的扩展,目标对象不需要实现接口(当然实现也可以),本例实现了接口 * 优点:1:解决了jdk动态代理的目标对象一定要实现接口的缺点。 * 2:CGLIB 是一个强大的,高性能的代码生成库,它可以在运行期扩展java类。 * 3:CGLIB 底层是使用小而快的字节码处理框架asm,来转换字节码,生成代理类。 * @author Administrator * */ public class TestCgLibProxy { public static void main(String[] args) throws InterruptedException { Enhancer enhancer=new Enhancer();//定义一个增强器 enhancer.setSuperclass(Plane.class);//设置目标对象的父类为代理类的父类 Movable m= (Movable) new Plane(); //Plane m=new Plane(); MyInterceptor callback=new MyInterceptor(m);//创建自定义拦截器对象 enhancer.setCallback(callback);//设置回调对象即是拦截器 Plane proxy=(Plane) enhancer.create();//创建代理对象 proxy.move(); } }
cglib代理总结:一般当目标对象没有实现接口,则用cglib代理,如果目标对象实现接口,则用jdk代理。
标签:png tor 不能 计算 mep author 定义 load public
原文地址:https://www.cnblogs.com/shareAndStudy/p/12820043.html