Java动态代理知识
切面: 包括切点和增强,切点是执行点的表示,增强包括增强逻辑代码和方位信息,其实增强也是一个一般的切面,只是此切面针对所有类的所有方法。(Spring目前只支持方法级别的增强)
两种动态代理实现切面技术
1.JDK动态代理 主要针对接口类型数据
把横切代码安置在MyInnovacationHandler中
public class MyInnovacationHandler implements InvocationHandler { private Waiter waiter;
//设置要调用的对象 public MyInnovacationHandler(Waiter waiter) { this.waiter = waiter; } @Override
// proxy表示代理对象 method表示要代理的方法 args表示目标方法参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("模拟调用 how are you " + args[0]);
//调用目标对象 Object object = method.invoke(waiter, args); return object; } }
调用JDK动态代理的代码
public static void textJDKProxy() {
//Waiter 表示接口 Waiter waiter = new NaviWaiter(); MyInnovacationHandler handler = new MyInnovacationHandler(waiter); Waiter proxy = (Waiter) Proxy.newProxyInstance(waiter.getClass().getClassLoader(), waiter.getClass().getInterfaces(), handler); proxy.greetTo("张"); proxy.serveTo("刘"); }
2. CGLIB动态代理技术:针对类数据代理,采用底层字节码技术,可以为一个类创建子类,在子类中采用拦截的技术拦截所有父类方法的调用 并顺势织入横切逻辑。
代理创建对象代码如下
public class CGlibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { // 设置父类的字节码 enhancer.setSuperclass(clazz); // 设置使用本对象的invoke方法 enhancer.setCallback(this); // 通过字节码技术动态创建子类实例 return enhancer.create(); } /** * @param o 表示目标类的实例 * @param method 目标类方法的反射对象 * @param objects d动态入参数 * @param methodProxy 方法代理 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // 织入横切代码 PerFormanceMonitor.begin(o.getClass().getName() + "." + method.getName()); // 调用目标方法 Object object = methodProxy.invokeSuper(o, objects); // 织入横切代码 PerFormanceMonitor.end(); return object; } }
调用代码
public static void proxy2() { //创建CGlibProxy代理对象 CGlibProxy cGlibProxy = new CGlibProxy();
//获得代理对象 其实就是此类的子类 ForumServiceImpl forumService = (ForumServiceImpl) cGlibProxy.getProxy(ForumServiceImpl.class);
//调用方法 forumService.removeFrume(10); forumService.removeTopic(10); }
注意: 两种动态代理方法的区别:JDK代理只针对接口类型数据,此中方法创建代理对象比CGlibProxy快,但代理对象的性能没有CGlibProxy方式高,所以在对象创建不频繁时(即sigleton),建议使用CGlibProxy方式实现动态代理.
针对CGlibProxy方式,只是通过创建子类的方式实现,因此对于Final类型类或具有final变量的类而言,这就容易出现问题。所以并非所有对象都能创建代理