动态代理机制:jdk与cglib

前言

按照代理类的创建时期,代理类可分为两种:

–静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

–动态代理类:在程序运行时,运用反射机制动态创建而成。

而动态代理又有cglib代理和jdk代理之分。

适用范围:

1、如果目标对象实现了接口,一般情况下采用JDK的动态代理

2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

3、如果目标对象没有实现了接口,必须采用CGLIB库

区别:

1、JDK动态代理利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。只能对实现了接口的类生成代理,而不能针对类。

2、CGLIB动态代理利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。是针对类实现代理在子类中覆盖指定类的方法。因为是继承,所以该类或方法最好不要声明成final 。

JDK代理

java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

Proxy类

Proxy类提供了创建动态代理类及其的实例的静态方法:
(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:

/**
*loader:指定动态代理类的类加载器
*interfaces:指定动态代理类需要实现的所有接口
*/
public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException

(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:

/**
*loader:指定动态代理类的类加载器
*interfaces:指定动态代理类需要实现的所有接口
*handler:指定与动态代理类关联的 InvocationHandler对象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException

以下两种方式都创建了实现Foo接口的动态代理类的实例:
/**** 方式一 ****/

 //创建InvocationHandler对象
 InvocationHandler handler = new MyInvocationHandler(...);
 //创建动态代理类
 Class proxyClass = Proxy.getProxyClass(
     Foo.class.getClassLoader(), new Class[] { Foo.class });
 //创建动态代理类的实例
 Foo foo = (Foo) proxyClass.
     getConstructor(new Class[] { InvocationHandler.class })
     .newInstance(new Object[] { handler });

/**** 方式二 ****/

 //创建InvocationHandler对象
 InvocationHandler handler = new MyInvocationHandler(...);
 //直接创建动态代理类的实例
 Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class[] { Foo.class },
                                          handler); 

InvocationHandler接口

InvocationHandler接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:

/**
*proxy:指定动态代理类实例
*method:指定被调用的方法
*args:指定被调用方法传递的参数
*invoke()方法的返回值表示被调用方法的返回值
*/
Object invoke(Object proxy,Method method,Object[] args) throws Throwable

示例

接口类和目标类

//接口类
public interface ISomeInterface {
	public String doSomething(String arg);
}
//持有方法的目标类
public class TargetClass implements ISomeInterface {
	public TargetClass() {
	}
	
	@Override
	public String doSomething(String arg) {
		System.out.println("正在执行doSomthing()方法");
		return "["+arg+"]";
	}
	
	public String dealSomething(String arg) {
		System.out.println("正在执行dealSomthing()方法");
		return "{"+arg+"}";
	}
}

JDK代理类

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

public class JDKProxy {
	public JDKProxy() {
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T getProxy(T target) {
		Class<?> klass = target.getClass();
		ClassLoader classLoader = klass.getClassLoader();
		Class<?>[] interfaces = klass.getInterfaces(); 
		return (T)Proxy.newProxyInstance(classLoader, interfaces, 
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("前置拦截");
						Object result = method.invoke(target, args);
						System.out.println("后置拦截");
						return result;
					}
				});
	}
}

测试类

import gw.proxy.jdk.core.JDKProxy;
import gw.proxy.some.ISomeInterface;
import gw.proxy.some.TargetClass;

public class JDKTest {

	public static void main(String[] args) {
		TargetClass target = new TargetClass();
        //参数target为被代理的对象
		ISomeInterface some = JDKProxy.getProxy(target);
		//some.doSomething("abcd")通过代理对象来调用实现的接口中的方法
		String str = some.doSomething("abcd");
		System.out.println(str);
	}
}

运行结果:
在这里插入图片描述

CGLib代理

CGLib代理是第三方库提供的动态代理,是基于子类的动态代理

要实现CGLib动态代理必须实现MethodInterceptor(方法拦截器)接口,并且通过Enhancer类中的create()方法创建代理对象

MethodInterceptor(方法拦截器)接口

public interface MethodInterceptor extends Callback{
    /**
    *obj:cglib生成的代理对象
    *method:被代理对象的方法
    *args:方法的参数
    *proxy:方法代理
    */
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable;
}

示例

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 {
	
	@SuppressWarnings("unchecked")
	public static <T> T getProxy(T target){
		Class<?> klass = target.getClass();
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(klass);//设置需要继承的类
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				System.out.println("前置拦截");
				Object result = method.invoke(target, args);
				System.out.println("后置拦截");
				return result;
			}
		});
		return (T) enhancer.create();
	}
}

Enhancer可以用来动态的生成一个类,这个类可以继承指定的一个类,实现指定的一些接口。同时,Enhancer在生成一个类之前需要指定一个Callback,当类方法调用时,方法的执行被分配给这个Callback,MethodInterceptor是一个使用比较多的继承自Callback的接口,它只有一个方法声明。

测试类:

import gw.proxy.cglib.core.CGLibProxy;
import gw.proxy.some.TargetClass;

public class CGLibTest {
	public static void main(String[] args) {
		TargetClass target = new TargetClass();
		
		TargetClass targetProxy = CGLibProxy.getProxy(target);
		String str = targetProxy.doSomething("abcd");
		System.out.println(str);
	}
}

运行结果:
在这里插入图片描述

总之,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。

参考博文:
https://www.cnblogs.com/sandaman2019/p/12636727.html
https://www.jianshu.com/p/46d092bb737d
https://blog.csdn.net/flyfeifei66/article/details/81481222
https://www.cnblogs.com/hujunzheng/p/5134478.html?utm_source=tuicool&utm_medium=referral

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值