Java动态代理原理分析

代理模式

       代理模式是 Java 常用的一个设计模式,目的是为了生成一个代理的对象,去代理某个真实的对象,真正执行任务的是代理对象,调用方把这个代理对象当成真正的某个对象来执行。且代理对象还能在真实对象的基础上实现增强,Spring AOP 的底层原理就是 Java 动态代理模式。

       代理的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

       代理模式最主要的就是有一个公共接口,一个具体的类,一个代理类,代理类持有具体类的实例,代为执行具体类实例方法。
在这里插入图片描述

动态代理

       在运行期,目标类加载后为接口动态生成代理类,将切面植入到代理类中。
       在java的动态代理机制中,有两个重要的类或接口,一个是Proxy类 、另一个则是 InvocationHandler接口。

标题动态代理类 Proxy

       Proxy这个类的作用就是用来动态创建一个代理对象,其中最重要的一个方法:

Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);
  • ClassLoader:指定的类加载器,把指定代理类的 .class 文件加载到内存,形成 Class 对象;

  • Class[] interfaces:指定要实现代理类的接口数组;

  • InvocationHandler:一定要实现的一个接口,它只有一个方法(invoke)需要实现,实现方法就是动态代理的具体实现。

       该方法动态创建实现了 interfaces 数组中所有指定接口的实现类对象,返回一个代理对象的实例。

       方法源码如下:

public static Object newProxyInstance(ClassLoader loader,
                                      Class>[] interfaces,
                                      InvocationHandler h)
  throws IllegalArgumentException
    {
		// 检查InvocationHandler不为空,如果为空则抛异常
        Objects.requireNonNull(h);

        final Class>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        // 利用指定类加载器与一组与指定接口相关代理类生成class对象
        Class<?> cl = getProxyClass0(loader, intfs);

		/*
         * 调用其构造函数指定的调用处理程序。
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
			// 获取代理对象的构造方法  $Proxy0(InvocationHandler h)
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
			// 生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法
            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);
        }
    }

InvocationHandler 接口

       InvocationHandler 是代理实例的调用处理程序实现的接口。

       每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

public Object invoke(Object proxy, Method method, Object[] args);
  • Object proxy:当前对象,即代理对象,在调用谁的方法;
  • Method method:当前被调用的方法(目标方法);
  • Object[] args:方法实参。

       定义一个接口:

public interface Animal {
	public void eat();
}

       定义一个 实现类,实现 User 接口:

public class Cat implements Animal {

	@Override
	public void eat() {
		System.out.println("eat fish!");

	}
}

       InvocationHandler 实现类

public class CatInvocationHandler<T> implements InvocationHandler {

	T target;

	public CatInvocationHandler(T target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		return method.invoke(target, args);
	}

}

       生成动态代理类:

        CatInvocationHandler<Cat> invocationHandler = new CatInvocationHandler<Cat>(new Cat());
		Animal cat = (Animal) Proxy.newProxyInstance(CatTest.class.getClassLoader(), new Class [] {Animal.class}, invocationHandler);
		// 这个方法打印 “eat fish!”
		cat.eat();

更多内容请关注微信公众号:全栈开发之技术栈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值