java设计模式基础--动态代理
动态代理的意义在于生成一个代理对象,来代理真实对象,从而控制真实对象的访问。比如你是以为软件工程师,客户带着需求去找公司,显然不会直接和你谈,而是去找商务,此时客户认为商务就代表公司。商务(代理对象)的意义在于可以进行谈判,比如软件的价格,交付,进度的时间节点,项目完成后追讨应收账款等。
所以说,代理的作用就是,在真实的对象访问之前或者之后加入对应的逻辑,或者根据其他规则控制是否使用真实对象。
因此,代理必须分为两个步骤:
代理对象和真实对象建立代理关系
实现代理对象的代理逻辑方法
在java中有多种动态代理技术,比如JDK,CGLIB,Javassist等。
一,JDK动态代理。
这是JDK自带的功能,它必须借助一个接口才能产生代理对象,所以先定义接口。
定义接口:
package proxy;public interface HelloWorld { public void sayHelloWorld();}
然后提供实现类,来实现接口:
package proxy;public class HelloWorldImpl implements HelloWorld { @Override public void sayHelloWorld() { System.out.println("Hello World"); }}
接下来就可以开始动态代理了。在JDK动态代理中,要实现代理逻辑类,必须去实现java.lang.reflect.InvocationHandler类,它里面定义了一个invoke方法。
实现代理逻辑类如下:
package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JdkProxyExample implements InvocationHandler { // 真实对象 private Object target = null; /** * 建立代理对象和真实对象的代理关系,并返回代理对象 * * @param target真实对象 * @return 代理对象 */ public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理方法逻辑 * * @param proxy * --代理对象 * @param method * --当前调度方法 * @param args * --当前方法参数 * @return 代理结果返回 * @throws Throwable * 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理逻辑方法"); System.out.println("在调度真实对象之前的服务"); Object obj = method.invoke(target, args);// 相当于调用sayHelloWorld方法 System.out.println("在调度真实对象之后的服务"); return obj; }}
Proxy.newProxyInstance方法的三个参数分别为:target本身的类加载器,target实现的接口,实现方法逻辑的代理类。
测试代码如下:
package proxy;import reflect.ReflectServiceImpl;public class ProxyTest { public static void main(String[] args) { JdkProxyExample jdk = new JdkProxyExample(); // 绑定关系,因为挂在接口HelloWorld下,所以声明代理对象HelloWorld proxy HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl()); // 注意,此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke里 proxy.sayHelloWorld(); }}
二,CGLB动态代理、
他的优势在于不需要提供接口,只需要一个非抽象类就可以实现动态代理。代码所引用的的jar包:cglib-3.2.5.jar,asm-5.0.4.jar
需要代理的类:
package proxy;public class CglibHelloWorld { public void sayHello(String name) { System.err.println("Hello " + name); }}
实现代理逻辑的类:
package proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxyExample implements MethodInterceptor { /** * 生成CGLIB代理对象 * * @param cls * -- Class类 * @return Class类的CGLIB代理对象 */ public Object getProxy(Class cls) { // CGLIB enhancer增强类对象 Enhancer enhancer = new Enhancer(); // 设置增强类型 enhancer.setSuperclass(cls); // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法 enhancer.setCallback(this); // 生成并返回代理对象 return enhancer.create(); } /** * 代理逻辑方法 * * @param proxy * 代理对象 * @param method * 方法 * @param args * 方法参数 * @param methodProxy * 方法代理 * @return 代理逻辑返回 * @throws Throwable异常 */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.err.println("调用真实对象前"); // CGLIB反射调用真实对象方法 Object result = methodProxy.invokeSuper(proxy, args); System.err.println("调用真实对象后"); return result; }}
测试代码:
package proxy;public class ProxyTest { public static void main(String[] args) { CglibProxyExample cpe = new CglibProxyExample(); CglibHelloWorld obj = (CglibHelloWorld)cpe.getProxy(CglibHelloWorld.class); obj.sayHello("张三"); }}
三,参考资料
《java EE 互联网框架整合开发》 杨开振 著
赞 (0)