栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

spring的静态代理和动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring的静态代理和动态代理

1,静态代理

静态代理的话,一共有三个部分,两个类和一个接口,其中两个类分别是代理类和被代理类,其中接口是用来定义代理类和被代理类中公共的方法,代理类中的方法,是对被代理类中的方法的增强和补充。
举个例子,假设有人卖车,在saleCar这个接口中定义了一个salecar的方法。

需要代理类和被代理类都去继承这个接口,但是在被代理类中,salecar方法只是简单的定义了"卖车"这一个步骤。

但是在卖车之前要生产车,卖车之后要对车进行包装,因此,就要定义一个代理类,对于salecar()方法进行增强。

在代理类中,将被代理对象注入,并且在sale方法中对其进行增强,下面是测试的结果:

结果:

可见,通过静态代理,可以对原本的方法进行增强,但是这种方法耦合度太高了,如果要卖表的话,需要在代理类中,将saleWatch这个被代理类的对象注入(重点),并且将生产和包装的增强逻辑再写一遍。
写卖表的接口:

卖表的被代理类:

在代理类中注入被代理类的对象,并且对salewatch进行增强。

测试结果:

然后,静态代理的话,如果一个代理对象对多个被代理对象进行同样的增强和补充,就需要在代理对象中对这些被代理对象的方法分别进行增强,耦合度太高了,因此就有了动态代理。

2,动态代理

在讲动态代理之前,需要介绍一个类和一个接口。

Proxy主要是通过newProxyInstance方法,返回一个代理对象。


ClassLoader loader:这个参数代表的是被代理类的类加载器,
Class[] interfaces:被代理类实现的接口数组。
InvocationHandler h:实现InvocationHandler这个接口的类的对象,直接传入this。

InvocationHandler这个接口只有一个方法,主要是在这个方法的内部进行方法的增强。


proxy:代理对象
method:要增强的方法
args:参数列表
修改代理类为如下:

package springAOP.Impl;

import springAOP.saleCar;
import springAOP.saleWatch;

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

//代理类
public class proxySaleCar implements InvocationHandler {

    Object factory;

    public Object getFactory() {
        return factory;
    }

    public void setFactory(Object factory) {
        this.factory = factory;
    }
    //根据传入的被代理对象返回一个代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(),this);
    }
    //方法增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBeforeSale();
        Object invoke = method.invoke(factory, args);
        doAfterSale();
        return invoke;
    }

    public void doBeforeSale(){
        System.out.println("生产");
    }
    public void doAfterSale(){
        System.out.println("包装");
    }


}

测试:

结果:

为什么会自动的运行invoke方法:

首先我们探究一下invoke方法中的参数proxy和我们创建的代理对象的关系:

输出参数proxy对象的字节码文件的名字。

输出生成代理对象的字节码的名称。
结果:

可以发现这两个其实是一个实例。

要搞清楚上面的问题,我们首先要看一下newProxyInstance创建代理对象的过程。
 public static Object newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h)
 

在该方法的内部,首先是通过下面代码:

 Class cl = getProxyClass0(loader, intfs);

调用了getProxyClass0方法, 该方法需要传入两个参数, 一个是类加载器,一个是接口数组,在方法getProxyClass0中会创建出一个类$Proxy0 ,并且创建出这个内部类的引用返回。这个就是代理实例。
这个代理实例的类继承了Proxy类,并且实现了传入的接口数组中的接口,对其中的方法进行了重写,继而进行增强。

	{
		try
		{
			super.h.invoke(this, m3, null);
			return;
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

在该方法中:super代表父类Proxy,h代表父类中的变量,也就是我们传进来的InvocationHandler接口实例,然后又调用了实例中的invoke方法,这个时候是不是就一目了然,这就是 InvocationHandler中的invoke方法会自动运行的原因,这是因为在代理类中的接口中方法内容重新定义了。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1036408.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号