最详细的代理讲解--JDK动态代理和cglib代理

1.代理相关的概念

代理模式

    代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

抽象主题角色

    声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题

代理主题(Proxy)角色

    代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象。

真实主题角色

   定义了代理角色所代表地真实对象

最详细的代理讲解--JDK动态代理和cglib代理_第1张图片

spring有两种代理方式:

   1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。

   2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

2.案例分析两种代理的异同

JDK动态代理

    注意事项:编写JDK代理类引用的是java的工具包lang中的反射包下的Proxy,不需要引入其他jar包,但是要注意不要倒错包了;import java.lang.reflect.Proxy; 目标对象实现了若干接口。

   两个接口类SayByeBye、SayGoodBye

package www.csdn.spring.proxy.jdk;

public interface SayByeBye {
	
	public void sayByeBye();

}

package www.csdn.spring.proxy.jdk;

public interface SayGoodBye {
	
	public void sayGoodBye(String content);

}
   这两个接口类的实现类SayByeImplement
package www.csdn.spring.proxy.jdk;

public class SayByeImpl implements SayGoodBye,SayByeBye {

	@Override
	public void sayGoodBye(String content) {
		System.out.println("say:"+content);
	}

	@Override
	public void sayByeBye() {
		System.out.println("say:拜拜!");
	}

}
  JDK代理类JDKProxy
package www.csdn.spring.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxy implements InvocationHandler {

	// 代理目标对象
	private Object target;

	// 创建目标对象的代理对象
	public Object createProxyInstance(Object target) {
		// 代理的目标对象
		this.target = target;
		// 创建代理对象
		// 1、定义代理类的类加载器
		// 2、代理类要实现的接口列表
		// 3、 指派方法调用的调用处理程序
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), this);
	}

	/**
	 * proxy:目标对象的代理实例,改代理实例不管运行多少次都是class $Proxy4 ;
	 * method:对于代理实例调用接口方法的Method实例;
	 * args:方法参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		/*
		 * 测试invoke方法的三个参数的含义
		 */
		System.out.println("proxy:"+proxy.getClass());
		System.out.println("method:"+method.getName());
		if(args!=null&&args.length>0){
			for(Object obj : args){
				System.out.println("args:"+obj);
			}
		}
		
		//声明返回值
		Object returnValue = null;
		beforeMethod();
		returnValue = method.invoke(target, args);
		afterMethod();
		return returnValue;
	}
	
	public void beforeMethod(){
		System.out.println("----方法执行之前的操作----");
	}
	public void afterMethod(){
		System.out.println("----方法执行之后的操作----");
	}
}
  测试类ProTest
package www.csdn.spring.proxy.jdk;

import org.junit.Test;

public class ProxyTest {

	@Test
	public void testSay() {
		
		//真是主题角色
		SayByeImpl sayByeImpl = new SayByeImpl();
		
		/*
		 * //不使用代理的情况
		 *  sayByeImpl.sayGoodBye("我要离婚!"); 
		 *  sayByeImpl.sayByeBye();
		 */
      
		//代理主题角色,这里用代理主题和真实主题实现的同样接口类来接收创建的代理主题,就是创建一个目标类
		SayGoodBye sayGoodBye = (SayGoodBye) new JDKProxy().createProxyInstance(sayByeImpl);
		SayByeBye sayByeBye = (SayByeBye) new JDKProxy().createProxyInstance(sayByeImpl);
	    sayGoodBye.sayGoodBye("受不了了,我要离婚!");
	    System.out.println("00000000000000000000000000000000000000000000000");
	    sayByeBye.sayByeBye();
	}

}



 

CGLIB做代理

    CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

    注意事项:使用cglib做代理,java中不想jdk动态代理那样给封装好了相应的类,他需要导入所依赖的jar包asm-3.3.jar、cglib-2.2.jar这两个jar包;目标对象没有实现任何接口

   目标类SayHello

package www.csdn.spring.proxy.cglib;

 

publicclass SayHello {

  

   publicvoid say(String content) {

      System.out.println("say:" + content);

   }

}

   cglib代理类CglibProxy

package www.csdn.spring.proxy.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 CglibProxy implements MethodInterceptor{
	
	private Object target;
	public Object createProxyInstance(Object target){
		this.target = target;
		//生成代理对象
		Enhancer  enhancer = new Enhancer();
		// 用于设置代理对象的父类
		enhancer.setSuperclass(this.target.getClass());
		//设置回调
		enhancer.setCallback(this);
		//创建代理对象 
		return enhancer.create();
	}

	/**
	 * proxy:目标对象代理的实例;
	 * method:目标对象调用父类方法的method实例 ;
	 * args:调用父类方法传递参数
	 * methodProxy:代理的方法去调用目标方法
	 */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		/*
		 * 测试invoke方法的四个参数的含义
		 */
		System.out.println("proxy:"+proxy.getClass());
		System.out.println("method:"+method.getName());
		System.out.println("methodProxy:"+methodProxy.getSuperName());
		if(args!=null&&args.length>0){
			for(Object obj : args){
				System.out.println("args:"+obj);
			}
		}
		
		//声明返回值
		Object returnValue = null;
		beforeMethod();
		//使用method和methodProxy参数都可以调用invoke方法,并且执行出来的效果一样
		//returnValue = methodProxy.invoke(target, args);
		returnValue = method.invoke(target, args);
		afterMethod();
		return returnValue;
	}
	
	public void beforeMethod(){
		System.out.println("----方法执行之前的操作----");
	}
	public void afterMethod(){
		System.out.println("----方法执行之后的操作----");
	}
}
   测试类proxyTest
package www.csdn.spring.proxy.cglib;

import org.junit.Test;

public class ProxyTest {

	@Test
	public void testSay() {
		
		//真是主题角色
		SayHello sayHello = new SayHello();
		//sayHello.say("嗨!你好啊!");
		
		//创建了一个 目标类的对象 ,jdk动态代理中创建的是接口类对象,cglib由于不实现任何接口,所以直接创建一个目标类的对象
		SayHello sh = (SayHello) new CglibProxy().createProxyInstance(sayHello);
		sh.say("嗨!你好啊!");
	}

}


 

你可能感兴趣的:(java,jdk,代理,cglib,杨凯专属频道)