动态代理模式
(1)什么是动态代理模式
动态代理中的代理类是由工具类活着工厂类动态生成的,代理关系是在程序运行过程中确立的。
(2)使用动态代理模式的要注意的几点
《1》动态代理模式中是不用程序员手工编写代理类的,是由工具或者工厂类动态生成的。
《2》目标对象是在客户类中创建的,因为工具类或者工厂类在动态的生成代理类时,是需要目标对象的(它要知道
为谁生成的代理类),而工具类或者工厂类是由客户类调用继而生成代理类,然后创建代理对象。
《3》由于目标对象是在客户类中创建的,所以这种代理模式是无法完成对目标类的保护和隐藏的功能,但是,如果
你的目的是为了在不修改目标类的前提下,增强目标方法的功能,可以使用动态代理模式达到需求。
《4》由于代理类是由工具类或者工厂类动态生成的,这个生成过程具有一般性,可以为任何的目标类生成代理类和
代理对象,然而不同的目标类其增强的需求是不一样的,为了完成其个性化的功能增强,代理类委托给另外一个
类E来实现,这个类E被称为委托类。
《5》动态代理和静态代理的区别
《1》使用静态代理的目的是为了保护和隐藏目标对象
《2》使用动态代理的目的是为了在不修改目标类的源码的基础之上,增强目标方法的业务逻辑功能。
动态代理中的代理类是由工具类活着工厂类动态生成的,代理关系是在程序运行过程中确立的。
(2)使用动态代理模式的要注意的几点
《1》动态代理模式中是不用程序员手工编写代理类的,是由工具或者工厂类动态生成的。
《2》目标对象是在客户类中创建的,因为工具类或者工厂类在动态的生成代理类时,是需要目标对象的(它要知道
为谁生成的代理类),而工具类或者工厂类是由客户类调用继而生成代理类,然后创建代理对象。
《3》由于目标对象是在客户类中创建的,所以这种代理模式是无法完成对目标类的保护和隐藏的功能,但是,如果
你的目的是为了在不修改目标类的前提下,增强目标方法的功能,可以使用动态代理模式达到需求。
《4》由于代理类是由工具类或者工厂类动态生成的,这个生成过程具有一般性,可以为任何的目标类生成代理类和
代理对象,然而不同的目标类其增强的需求是不一样的,为了完成其个性化的功能增强,代理类委托给另外一个
类E来实现,这个类E被称为委托类。
《5》动态代理和静态代理的区别
《1》使用静态代理的目的是为了保护和隐藏目标对象
《2》使用动态代理的目的是为了在不修改目标类的源码的基础之上,增强目标方法的业务逻辑功能。
《3》二者的代理关系的确立的时间不同,静态代理是程序运行前,动态代理是在程序运行过程中。
(3)实现
《1》首先要在客户类中创建目标对象,然后调用以下方法动态的生成代理类的代理对象,该方法的返回值是
返回一个指定接口的代理类实例。
Proxy.newProxyInstance(loader, interfaces, h)(这三个参数的含义:loader 是目标类的类加载器
interfaces是目标类实现的所有接口,h,是只委托类对象)代码如下:
//动态生成代理对象
ISomeService someServiceImpl = (ISomeService) Proxy.newProxyInstance(
//目标类的类加载器,我们也可以写成
/*SomeServiceImpl.class.getClassLoader(),
*我们一般用第一种,这样方便我们用目标对象。*/
target.getClass().getClassLoader(),
//目标类实现的所有接口
target.getClass().getInterfaces(),
//代理类的委托对象
new ServiceProxyEntrust(target));
委托类在定义的时候,必须要实现InvocationHandler接口,这个接口中只有一个invoke方法,所以我们应该重写这个方法
public Object invoke(Object proxy,Method method,Object[] args)(其中参数proxy是指代理对象
method 是目标方法,args是指目标方法的参数),目标方法的执行过程如下:
package com.abc.entrusts;
(3)实现
《1》首先要在客户类中创建目标对象,然后调用以下方法动态的生成代理类的代理对象,该方法的返回值是
返回一个指定接口的代理类实例。
Proxy.newProxyInstance(loader, interfaces, h)(这三个参数的含义:loader 是目标类的类加载器
interfaces是目标类实现的所有接口,h,是只委托类对象)代码如下:
//动态生成代理对象
ISomeService someServiceImpl = (ISomeService) Proxy.newProxyInstance(
//目标类的类加载器,我们也可以写成
/*SomeServiceImpl.class.getClassLoader(),
*我们一般用第一种,这样方便我们用目标对象。*/
target.getClass().getClassLoader(),
//目标类实现的所有接口
target.getClass().getInterfaces(),
//代理类的委托对象
new ServiceProxyEntrust(target));
委托类在定义的时候,必须要实现InvocationHandler接口,这个接口中只有一个invoke方法,所以我们应该重写这个方法
public Object invoke(Object proxy,Method method,Object[] args)(其中参数proxy是指代理对象
method 是目标方法,args是指目标方法的参数),目标方法的执行过程如下:
package com.abc.entrusts;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.abc.service.ISomeService;
import com.abc.utils.SystemUtil;
//委托类,必须要实现InvocationHandler接口
public class ServiceProxyEntrust implements InvocationHandler {
//把代理对象声明成成员变量
private ISomeService target;
//通过有参构造器把代理对象传递进来
public ServiceProxyEntrust(ISomeService target) {
super();
this.target = target;
}
/**
* proxy:代理对象
* method:目标方法
* args:目标方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//植入交叉逻辑
SystemUtil.doTx();
//通过反射执行目标方法
Object result = method.invoke(target, args);
//植入交叉逻辑
SystemUtil.doLog();
return result;
}
}
//注意,对于委托类中的代理对象,我一般是采用把代理对象声明成成员变量,然后通过委托类的有参构造器传入的。
import java.lang.reflect.Method;
import com.abc.service.ISomeService;
import com.abc.utils.SystemUtil;
//委托类,必须要实现InvocationHandler接口
public class ServiceProxyEntrust implements InvocationHandler {
//把代理对象声明成成员变量
private ISomeService target;
//通过有参构造器把代理对象传递进来
public ServiceProxyEntrust(ISomeService target) {
super();
this.target = target;
}
/**
* proxy:代理对象
* method:目标方法
* args:目标方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//植入交叉逻辑
SystemUtil.doTx();
//通过反射执行目标方法
Object result = method.invoke(target, args);
//植入交叉逻辑
SystemUtil.doLog();
return result;
}
}
//注意,对于委托类中的代理对象,我一般是采用把代理对象声明成成员变量,然后通过委托类的有参构造器传入的。
总结:我们来谈谈JDK的Proxy的动态代理执行的过程,当我们动态的生成了代理对象之后,当我们调用了代理对象的代理方法时,系统会自动调用委托类的invoke方法,在这个invoke方法中,我们可以通过植入交叉逻辑来达到个性化增强目标类的业务逻辑功能,动态生成的代理对象的名字有3部分构成"$ + Proxy + 数字",数字表示的是当前JDK的Proxy所生成的代理类的索引,索引是从0开始计数的,(当然,代理类在创建的过程中,会自动Cache内存中检测该代理类是否已经被创建,如果是,便会把之前创建的代理类的索引直接复制,如果没有创建,那么便会创建)
系统为什么会自动加载Invoke方法?
因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的ISomeService接口,
在实现ISomeService接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。
动态代理的执行流程如下: