动态代理模式:
动态代理的意义在于生成一个代理对象,来代理真实的对象,在真实对象访问之前或者之后加入对应的逻辑,或者控制是否使用真实的对象。
为了实现代理的功能,代理的两个步骤为:
l 代理对象和真实对象之间建立代理关系
l 实现代理对象的逻辑方法
在java中有多种动态代理技术,其中常用的动态代理技术有两种:一种是JDK动态代理技术(jdk自带的功能),另一种是CGLIB(第三方提供)
一. JDK动态代理
Java.lang.reflect.*提供的动态代理方式,其必须定义一个接口才能产生代理对象。
- 定义接口
package proxy; public interface Helloworld { public void sayHelloworld(); }
2.接口实现类
package proxy; public class HelloworldImpl implements Helloworld{ @Override public void sayHelloworld() { // TODO Auto-generated method stub System.out.println("Hello world"); } }
3.建立JDK动态代理,根据刚开始我们说的两个步骤分别实现bind和invoke方法
package proxy; import java.lang.reflect.*; public class JdkProxyExample implements InvocationHandler{ public Object target = null; // 建立真实对象和代理对象之间的代理关系,并返回代理关系 public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // @Override // 代理方法逻辑 // @param proxy 代理对象 // @param method 当前调度方法 // @param args 当前方法参数 // @return 代理结果返回 // @throes Throwable 异常 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; } }
步骤一:建立代理对象与真实对象之间的代理关系(bind方法)方法里首先使用了类属性保存了真实对象 在通过如下代码生成代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
NewProxyInstance包含三个参数:
l Target.getClass().getClassLoader():真实对象的类加载器,
l Target.getClass().getInterfaces():把生成的代理对象挂在Helloworld的接口上
l This:定义实现方法咯及的代理类,this表示当前对象,它必须是实现InvocationHandler接口的invoke方法,是动态代理逻辑方法的现实方法。
步骤二:实现代理逻辑方法:
Invoke方法的参数含义:
Proxy:代理对象,即bind方法生成的对象
Method:当前调用的方法
Args:调度方法的参数
我们使用了代理对象的方法后,它就会进入invoke方法里面
Object obj = method.invoke(target, args);//相当于调用了真实对象的sayHelloworld方法
这是通过反射实现对真实方法的调用。
测试JDK动态代理代码:
package proxy; public class TestJdkProxy { public static void main(String[] args) { JdkProxyExample jdk = new JdkProxyExample(); Helloworld proxy = (Helloworld)jdk.bind(new HelloworldImpl()); proxy.sayHelloworld(); } }
结果:
-
二. CGLIB动态代理:
CGLIB动态代理的优势在于不需要提供接口,只需要一个非抽象类就能实现动态代理。
非抽象类代码如下:
package cglib; public class Helloworld { public void sayHelloworld(String name) { System.out.println("Hello,"+name); } }
Cglib动态代理:
package cglib; 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{ public Object getProxy(Class cls) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(cls); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("调用真实对象前"); Object result = methodProxy.invokeSuper(proxy,args); System.out.println("调用真实对象后"); return result; } }
这里用了CGLIB的加强者Enhancer,通过设置超类的方法建立代理关系,通过setCallback方法设置代理类,this指当前对象,实现MethodInterceptor的方法(intercept)
方法参数含义:
Proxy:代理对象
Method:方法
Args:方法参数
MethodProxy:方法代理
Return 返回代理逻辑
测试类:
package cglib; public class TestCglibProxy { public static void main(String[] args) { CglibProxyExample Cglib = new CglibProxyExample(); Helloworld proxy = (Helloworld)Cglib.getProxy(Helloworld.class); proxy.sayHelloworld("fanl"); } }