代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。
换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。 客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口。
对于代理模式,需要注意以下几点:
(1)代理类和目标类要实现同一个接口,即业务接口。
(2)客户类对目标类的调用均是通过代理类完成的。
(3)代理类的执行既执行了对目标类的增强业务逻辑,又调用了目标类的主业务逻辑。
根据代理关系建立的时间不同,可以将代理分为两类:静态代理与动态代理。
静态代理:
静态代理是指,代理类在程序运行前就已经定义好,其与目标类的关系在程序运行前就已经确立。
1 package com.tongji.csis.qjj; 2 3 //业务接口 4 public interface ISomeService { 5 String doSome(); 6 String doSecond(); 7 }
1 package com.tongji.csis.qjj; 2 3 //目标类,主要实现了业务接口的主业务逻辑,这些方法称为目标方法 4 public class SomeServiceImpl implements ISomeService { 5 6 @Override 7 public String doSome() { 8 System.out.println("执行doSome()"); 9 return "I Love you"; 10 } 11 12 @Override 13 public String doSecond() { 14 System.out.println("执行doSecond()"); 15 return "China"; 16 } 17 18 }
1 package com.tongji.csis.qjj; 2 3 //静态代理类 4 //要求静态代理类与目标类实现相同的业务接口 5 public class SomeServiceProxy implements ISomeService { 6 //声明业务接口对象 7 private ISomeService target; 8 9 public SomeServiceProxy() { 10 super(); 11 } 12 //业务接口对象作为构造器参数,用于接收目标对象 13 public SomeServiceProxy(ISomeService target) { 14 super(); 15 this.target = target; 16 } 17 18 @Override 19 public String doSome() { 20 return target.doSome(); 21 } 22 //代理方法,实现对目标方法的功能增强 23 @Override 24 public String doSecond() { 25 return target.doSecond().toUpperCase(); 26 } 27 28 }
1 package com.tongji.csis.qjj; 2 3 public class MyTest { 4 5 public static void main(String[] args) { 6 //定义目标对象 7 ISomeService target = new SomeServiceImpl(); 8 //定义目标对象的代理对象 9 ISomeService serviceProxy = new SomeServiceProxy(target); 10 String result1 = serviceProxy.doSome(); 11 String result2 = serviceProxy.doSecond(); 12 System.out.println(result1 + "," + result2); 13 } 14 15 }
JDK动态代理:
动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(如代理工厂类)在程序运行时由JVM根据反射等机制动态生成的。代理对象与目标对象的代理关系在程序运行时才确立。
对比静态代理,静态代理是指在程序运行前就已经定义好了目标类的代理类。代理类与目标类的代理关系在程序运行之前就确立了。
动态代理的实现方式常用的有两种:使用JDK的Proxy,与通过CGLIB生成代理。 通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance(),依据目标对象、业务接口及业务增强逻辑三者,自动生成一个动态代理对象。
JDK动态代理代码中的业务接口代码和目标类代码和上面相同;
1 package com.tongji.csis.qjj; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 //主业务增强逻辑类 7 public class MyExtension implements InvocationHandler { 8 9 private Object target; 10 11 public MyExtension(Object target) { 12 super(); 13 this.target = target; 14 } 15 16 //增强方法,proxy:代理对象;method:目标方法;args:目标方法的参数列表 17 @Override 18 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 19 String result = (String) method.invoke(target,args); 20 if ("doSecond".equals(method.getName())) { 21 result = result.toUpperCase(); 22 } 23 return result; 24 } 25 26 }
1 package com.tongji.csis.qjj; 2 3 import java.lang.reflect.Proxy; 4 5 public class MyTest { 6 7 public static void main(String[] args) { 8 9 //定义目标对象 10 ISomeService target = new SomeServiceImpl(); 11 //定义目标对象的代理对象 12 ISomeService serviceProxy = (ISomeService) Proxy.newProxyInstance( 13 target.getClass().getClassLoader(), //获取目标对象的类加载器 14 target.getClass().getInterfaces(), //获取目标对象的所有接口 15 new MyExtension(target)); //增强业务逻辑 16 17 String result1 = serviceProxy.doSome(); 18 String result2 = serviceProxy.doSecond(); 19 System.out.println(result1 + "," + result2); 20 } 21 22 }
JDK的动态代理,底层是通过“工厂+反射机制”,动态创建静态代理中的代理类。
CGLIB动态代理:
使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。
但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final的类。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类。CGLIB是通过对字节码进行增强来生成代理的。
CGIB动态代理代码中没有业务接口代码;
1 package com.tongji.csis.qjj; 2 3 //目标类 4 public class SomeService { 5 6 public String doSome() { 7 System.out.println("执行doSome()"); 8 return "I Love you"; 9 } 10 11 public String doSecond() { 12 System.out.println("执行doSecond()"); 13 return "China"; 14 } 15 16 }
1 package com.tongji.csis.qjj; 2 3 import java.lang.reflect.Method; 4 5 import net.sf.cglib.proxy.Enhancer; 6 import net.sf.cglib.proxy.MethodInterceptor; 7 import net.sf.cglib.proxy.MethodProxy; 8 9 //CGLIB代理类的生成工厂 10 public class CglibProxyFactory implements MethodInterceptor { 11 12 private SomeService target; 13 14 public CglibProxyFactory() { 15 super(); 16 } 17 18 public CglibProxyFactory(SomeService target) { 19 super(); 20 this.target = target; 21 } 22 23 //用于创建Cglib代理对象 24 public SomeService myProxyCreator() { 25 //增强器:指定父类,既要增强的目标类,并指定回调接口对象 26 Enhancer enhancer = new Enhancer(); 27 enhancer.setSuperclass(SomeService.class); 28 enhancer.setCallback(this); 29 return (SomeService) enhancer.create(); 30 } 31 32 @Override 33 public Object intercept(Object proxy, Method method, Object[] args, 34 MethodProxy methodProxy) throws Throwable { 35 String result = (String) method.invoke(target,args); 36 if ("doSecond".equals(method.getName())) { 37 result = result.toUpperCase(); 38 } 39 return result; 40 } 41 }
1 package com.tongji.csis.qjj; 2 3 public class MyTest { 4 5 public static void main(String[] args) { 6 //定义目标对象 7 SomeService target = new SomeService(); 8 //定义目标对象的代理对象 9 SomeService serviceProxy = new CglibProxyFactory(target).myProxyCreator(); 10 String result1 = serviceProxy.doSome(); 11 String result2 = serviceProxy.doSecond(); 12 System.out.println(result1 + "," + result2); 13 } 14 15 }