看了 stamen的学习spring必要的java基础知识,感觉受益匪浅,也把我学到的记录下来,巩固下加深记忆,也便于以后回来看。
动态代理的应用仔细想起来感觉不是很多,我能想到的就是写日志,事物管理,不过这种模式的话在以后的工作中可能会用得到。
java的动态代理有两种机制,一种是jdk的动态代理,另一种就是cglib的动态代理,两者的区别在于jdk动态代理是基于接口实现的,而cglib跳过了接口直接支持类的代理。
先说下我对动态代理的理解吧,用下面一个图 :
(代理调用图)
首先通过我们的对象生成代理对象,并将实现了我们需要的业务逻辑对象的类织入到代理对象中,然后代理对象调用我们类的方法,然后织入的对象拦截到我们的方法,在我们执行的方法前或执行方法后先调用我们已经写好的逻辑,然后通过反射的invoke方法调用被代理对象的方法,从而实现了动态代理调用。打个比方,就像我们买票,我们直接去火车站买看做是直接调用,但是我们想知道我们什么时候去的,还不想在我们自己的逻辑里写,那我们就可以去找代购点,它就相当于我们的代理,我在他这买车票,在买票前或买票后 他帮我们记下我们啥时候买的票,再调用我们买票的方法拿钱给票,这样既不用我们自己去记什么时候买的票,又有人帮我们记下了,就实现了代理切入。
利用动态代理技术的话,去执行方法的对象就一定是代理对象,那么使用的重点就变成了如何去创建代理对象。下面看下两种方式如何去创建自己的代理对象。
一、jdk代理对象的创建:
首先了解下jdk创建代理的方法,如下代码,它需要三个参数,第一个参数是被创建代理类的加载器,第二个是他实现的接口,第三个是实现InvocationHander接口的一个类,我们的操作代码其实就是写到这个类中,然后利用反射去调用被代理类的方法。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
看下执行的代码,从stamen的博客中摘取的代码,其中③-1处可以写我们自己的处理代码。
public class PerformanceHandler implements InvocationHandler {//①实现InvocationHandler private Object target; public PerformanceHandler(Object target){ //②target为目标的业务类 this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) ③ throws Throwable { //③-1 Object obj = method.invoke(target, args);// ③-2通过反射方法调用业务类的目标方法 //③-1 return obj; } }
然后是调用的代码,也是摘取的。
public class TestForumService { public static void main(String[] args) { //①希望被代理的目标业务类 ForumService target = new ForumServiceImpl(); //②将目标业务类和横切代码编织到一起 PerformanceHandler handler = new PerformanceHandler(target); //③根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例 ForumService proxy = (ForumService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); //④调用代理实例 proxy.removeForum(10); proxy.removeTopic(1012); } }
二、CGLib方式实现动态代理
CGLib创建代理对象所依靠的是net.sf.cglib.proxy.Enhancer对象,Enhancer的 setSuperclass方法确定要创建代理的类,setCallback方法确定执行代理方法的类,然后调用create()方法去创建并返回CGLib代理对象,setCallback方法中的参数是要继承net.sf.cglib.proxy.Callback接口的并实现intercept方法的类,在这里我们用创建一个类继承MethodInterceptor接口,MethodInterceptor接口是继承Callback接口的,也就是间接地继承了Callback接口。然后在我们用代理类去调用方法是,就可以执行 intercept方法中我们加入的逻辑,看下代码可能会更清晰,仍然摘取。。。。
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { enhancer.setSuperclass(clazz); //① 设置需要创建子类的类 enhancer.setCallback(this); return enhancer.create(); //②通过字节码技术动态创建子类实例 } //③拦截父类所有方法的调用 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { //③-1 Object result=proxy.invokeSuper(obj, args); ③-2 //③-1 return result; } }
上面的 ③-1处可以加入我们自己的逻辑。 下面是利用代理执行操作代码,go on 摘取,手懒啊!!!!
package com.baobaotao.proxy; import java.lang.reflect.Proxy; public class TestForumService { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); ForumServiceImpl forumService = ① (ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class); forumService.removeForum(10); forumService.removeTopic(1023); } }
这样就实现了CGLib的代理方式。在上面的代码中 CGLibProxy中的getProxy是可以提出到main方法中去实现的,具体的执行就像下面这样
package com.baobaotao.proxy; import java.lang.reflect.Proxy; public class TestForumService { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(ForumServiceImpl); enhancer.setCallback(CglibProxy); ForumServiceImpl forumService = (ForumServiceImpl )enhancer.create(); forumService.removeForum(10); forumService.removeTopic(1023); } }