JDK动态代理和CGLIB动态代理

JDK动态代理:

概述:
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。详细介绍请参考:java设计模式之代理模式。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

  • 在java的动态代理机制中一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class).

文章参考引用自:https://blog.csdn.net/xiaokang123456kao/article/details/77679848

    1. 声明接口
package com.feifan.jdk;

import java.util.List;

/**
 * 需要动态代理的接口
 * @author Donald
 * 2018-11-27 22:23:34
 */
public interface ProxyInterface {
	public String sayHello();
	public List<String> listShow();
	public void sayNothing(String ... strings);
	public String arrayReturn(Object[] args);
}

    1. 声明实现类
package com.feifan.jdk;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 具体的实现类
 * @author Donald
 * 2018-11-27 22:27:03
 */
public class ProxyInterfaceImpl implements ProxyInterface {

	@Override
	public String sayHello() {
		return "sayHello ====NoParmater";
	}

	@Override
	public List<String> listShow() {
		List<String> list= new ArrayList<>();
		list.add("wang");
		list.add("ming");
		list.add("huhu");
		return list;
	}

	@Override
	public String arrayReturn(Object[] args) {
		String string=Arrays.toString(args);
		return string;
	}

	@Override
	public void sayNothing(String... strings) {
		System.out.println(Arrays.toString(strings));
	}
	
}

    1. 声明InvokeHandler 实现类
package com.feifan.jdk;

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


/**
 *每次生成动态代理类对象都需要指定一个实现InvocationHandler接口的调用处理器对象
 * @author Donald
 * 2018-11-27 22:37:43
 */
public class InvokHandler implements InvocationHandler{

	//这个就是我们需要代理的真实对象。
	private Object subject;
	
	
	public InvokHandler(Object subject) {
		this.subject = subject;
	}


	/**
	 * 一个动态代理类都必须要实现InvocationHandler这个接口,
	 * 并且每个代理类的实例都关联了一个handler,当我们通过代理对象调用一个方法的时候,
	 * 这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
	 * 我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
	 * @param proxy 指代JDK动态生成的最终代理对象
	 * @param method 指代的是我们所要调用真实对象的某个方法的Method对象
	 * @param args 指代的是调用真实对象某个方法时接受的参数
	 * @return method对应的方法 的返回值
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result=null;
		try {
			System.out.println("前置通知:当前调用的方法是:"+method.getName());
			//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象
			//关联的handler对象 的invoke方法进行调用。
			result=method.invoke(subject, args);//指定被代理的对象和参数
			System.out.println("后置通知:程序正常执行之后result...."+result);
		} catch (Exception e) {
			System.out.println("方法执行异常通知Exception:"+e.getMessage());
		}
		System.out.println("方法执行了通知");
		return result;
	}

}

  • 测试
  • //loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来生成代理对象进行加载
    //interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    //h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,间接通过invoke来执行
package com.feifan.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;

public class TestJDKProxy {
	
	@Test
	public void JDKTest() {
		//1.被代理对象
		ProxyInterface proxyInterface= new ProxyInterfaceImpl();
		//2.InvocationHandler 的实现类
		InvokHandler invokHandler=new InvokHandler(proxyInterface);
		
		//3.调用Proxy的静态方法
		/**
		 * public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
		 * ClassLoader loader,类加载器
		 * Class<?>[] interfaces,目标对象实现的接口
         * InvocationHandler h:InvocationHandler 的实现类
        
		 */
		ProxyInterface newProxy = (ProxyInterface)Proxy.newProxyInstance(proxyInterface.getClass().getClassLoader()
								, proxyInterface.getClass().getInterfaces()
								, invokHandler);
		//此处会调用newProxy的toString 方法
		System.out.println("newProxy动态代理对象内存地址:"+newProxy+"\t>>newProxyname:"+newProxy.getClass().getSimpleName());
		
	
		List<String> listShow = newProxy.listShow();
		System.out.println("listShow"+listShow);
		System.out.println("-------------------");
		
		newProxy.sayNothing("sss","sds","ssK");
		System.out.println("-------------------");
		
		Object [] kObjects={"ddd","dd","ff"};
		String arrayReturn = newProxy.arrayReturn(kObjects);
		System.out.println(arrayReturn);
		
	}

}

  • 结果:
    在这里插入图片描述
    JDK内置的Proxy动态代理可以在运行时动态生成字节码,而没必要针对每个类编写代理类。中间主要使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态方法,参数说明如下:

使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。


CGLIB 代理实现:

CGLIB是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理.
CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码。

  • 实体类
package com.feifan.cglib;

public class CglibEntity {
		public void cg() {
			System.out.println("CGLIB 代理类 无参");
		}
		
		public void cg1(String name)
		{
			System.out.println("CGLIB 代理测试:name"+name);
		}
		
		public void cg2() {
			int k=1/0;
		}
}

  • 动态代理类
package com.feifan.cglib;

import static org.hamcrest.CoreMatchers.nullValue;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 动态代理类、实现一个方法拦截器接口
 * @author Donald
 * 2018-11-28 20:57:11
 */
public class CglibDynamic implements MethodInterceptor{

	//被代理的对象
	Object targetObject;
	
	//动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例。
	public Object getCglibObject(Object object)
	{
		targetObject=object;
		//增强器,动态代码生成器
		Enhancer enhancer= new Enhancer();
		//回调方法
		enhancer.setCallback(this);
		//设置生成类的父类类型
		enhancer.setSuperclass(targetObject.getClass());
		//动态生成字节码并返回代理对象
		Object object2 = enhancer.create();
		//System.out.println(object2+">>>>");
		return object2;
	}
	
	//拦截方法
	/**
	 * Object为由CGLib动态生成的代理类实例,
	 * Method为上文中实体类所调用的被代理的方法引用,
	 * Object[]为参数值列表,
	 * MethodProxy为生成的代理类对方法的代理引用。
	 * 返回:从代理实例的方法调用返回的值。
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		Object result =null;
		// 被织入的横切内容,开始时间Before
		System.out.println("cglib方法执行之前");
		//调用方法
		try {
			result = proxy.invoke(targetObject, args);
			System.out.println("CGLIB目标方法正常执行了"+proxy.getSignature().getName());
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("cglib方法执行异常");
		}
		System.out.println("cglib目标方法执行了");
		return result;
	}

}
  • 测试方法
package com.feifan.cglib;

import org.junit.Test;

public class CglibTest {
	
	@Test
	public void cglibTest() {
		CglibEntity cglibEntity= new CglibEntity();
		CglibDynamic cglibDynamic=new CglibDynamic();
		System.out.println("------");
		CglibEntity cglibTarget = (CglibEntity)cglibDynamic.getCglibObject(cglibEntity);
		System.out.println(cglibTarget+"------");
		cglibTarget.cg1("HIJI");
		cglibTarget.cg2();
	}

}
  • 测试结果
    在这里插入图片描述
    代码参考:

链接:https://pan.baidu.com/s/10wC0L53eVsc6EeIs2JiQDA
提取码:lwnd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值