Java 动态代理实现

     看了 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);
	}
}
 

 

猜你喜欢

转载自liuzl121.iteye.com/blog/1756572