jdk动态代理实现原理

什么是静态代理

静态代理的实现

  • 代理类通过实现与目标对象相同的接口,并在类中维护一个目标对象
  • 在代理类中,通过构造器塞入目标对象,赋值给代理对象
  • 执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能
    具体的实现查看:https://www.cnblogs.com/cC-Zhou/p/9525638.html

JDK 动态代理是什么

JDK 的动态代理是基于拦截器和反射来实现的。JDK代理是不需要第三方库支持的,只需要 JDK 环境就可以进行代理

  • 必须实现 InvocationHandler 接口
  • 使用 Proxy.newProxyInstance 产生代理对象
  • 被代理的对象必须要实现接口

JDK 动态代理简单实现

接口

public interface IHello {
   
    void sayHello();
}

接口实现类

public class HelloImpl implements IHello {
   

    @Override
    public void sayHello() {
   
        System.out.println("Hello world!");
    }
}

实现 InvocationHandler 接口

public class MyInvocationHandler implements InvocationHandler {
   
 
    /*目标对象*/
    private Object target;
 
    public MyInvocationHandler(Object target){
   
        this.target = target;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
        System.out.println("------插入前置通知代码-------------");
        // 执行相应的目标方法
        Object rs = method.invoke(target,args);
        System.out.println("------插入后置处理代码-------------");
        return rs;
    }
}

测试

public class MyProxyTest {
   

    public static void main(String[] args)
            throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
   
 
        IHello  iHello2 = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), // 加载接口的类加载器
                new Class[]{
   IHello.class}, // 一组接口
                new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
        iHello2.sayHello();
    }
}

结果:
------插入前置通知代码-------------
Hello world!
------插入后置处理代码-------------

JDK 动态代理源码分析

Proxy.newProxyInstance() 方法

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
	throws IllegalArgumentException {
   
	
	// 如果h为空直接抛出空指针异常,之后所有的单纯的判断null并抛异常,都是此方法
	Objects.requireNonNull(h);
	// 拷贝类实现的所有接口
    final Class<?>[] intfs = interfaces.clone();
	// 获取当前系统安全接口
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
   
	// Reflection.getCallerClass 返回调用该方法的方法的调用类;loader:接口的类加载器
	// 进行包访问权限、类加载器权限等检查
	checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
	}
 
	// 查找或生成指定的代理类
	Class<?> cl = getProxyClass0(loader, intfs);
 
	// 用指定的调用处理程序调用它的构造函数
	try {
   
		if (sm != null) {
   
			checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
	   	/**
	   	 * 获取代理类的构造函数对象。
	     * constructorParams是类常量,作为代理类构造函数的参数类型,常量定义如下:
	     * private static final Class<?>[] constructorParams = { InvocationHandler.class };
	     */
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		final InvocationHandler ih = h;
		if (!Modifier.isPublic(cl.getModifiers())) {
   
			AccessController.doPrivileged(new PrivilegedAction<Void>() {
   
            	public Void run() {
   
                	cons.setAccessible(true);
                        return null;
                }
            });
		}
		// 根据代理类的构造函数对象来创建需要返回的代理类对象
		return cons.newInstance(new Object[]{
   h});
	} catch (IllegalAccessException|InstantiationException e) {
   
		throw new InternalError(e.toString(), e);
	} catch (InvocationTargetException e) {
   
		Throwable t = e.getCause();
		if (t instanceof RuntimeException) {
   
        	throw (RuntimeException) t;
		} else {
   
            throw new InternalError(t.toString(), t);
        }
	} catch (NoSuchMethodException e) {
   
		throw new InternalError(e.toString(), e);
	}
}

newProxyInstance() 方法帮我们执行了生成代理类,获取构造器,生成代理对象这三个操作

  • 生成代理类ÿ
  • 6
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值