动态代理
- 特点:字节码随用随创建,随用随加载
- 作用:不修改源码的基础上对方法增强(和装饰器什么关系呢?)
- 分类:
- 基于接口的动态代理
- 基于子类的动态代理
基于接口的动态代理
- 涉及的类:Proxy
- 提供者:JDK官方
- 如何创建代理对象:
- 使用Proxy类中的newProxyInstance方法
- 创建代理对象的要求:
- 被代理类最少实现一个接口,如果没有则不能使用
- newProxyInstance方法的参数:
- ClassLoader:类加载器
- 用于加载代理对象字节码,和被代理对象使用相同类加载器-固定写法
- Class[]:字节码数组-其实就是接口的数组
- 用于让代理对象和被代理对象有相同的方法-固定写法
- InvocationHandler:用于提供增强代码
- 让我们如何写代理的地方。一般用该接口的实现类,或者直接一个匿名内部类
- 此接口的实现类都是谁用谁写
- ClassLoader:类加载器
main方法:
final Producer producer=new Producer();
IProducer proxy=(IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
/**
*
* @param proxy 代理对象的引用
* @param method 当前执行的被代理对象的方法
* @param args 当前方法的参数
* @return 和被代理对象方法返回值相同
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Float money=(Float)args[0];
Object rtValue=null;
if(method.getName().equals("saleService")) {
rtValue = method.invoke(producer, money * 0.8f);
}
return rtValue;
}
});
proxy.saleService(10000f);
- 调用的时候不是直接向
厂家
调用,而是通过厂家
实现的接口调用方法。 - 调用该接口下的任意方法都会经过invoke方法,而他里面实现了
代理商
调用厂家
的方法,还有些附加服务。这样在代理商
调用厂家
的方法的时候,就可以动些手脚,加点东西,实现了不修改厂家
的方法,但是实现了我们想要的功能。 -
谁用谁创建,意思就是,谁要添加附加的服务,谁就创建一个代理对象,去代理
厂家
,这样不修改厂家
的方法,但是实现了我们想要的功能。 - newProxyInstance会返回一个proxy的实例,是以被代理对象的类加载器创建的,实现了特定接口的实例。最后通过接口引用,就可以保证只调用接口中有的方法。
基于子类的动态代理
- 涉及的类:Enhancer
- 提供者:第三方cglib库
- 如何创建代理对象:
- 使用Enhancer类的create方法
- 创建代理对象的要求:
- 被代理类不能是最终类(没有final修饰)
- create方法的参数:
- Class:字节码
- 用于指定被代理对象的字节码(getClass()获取)
- Callback(接口):用于提供增强的代码
- 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
- 此接口的实现类都是谁用谁写。
- 我们一般写的都是该接口的子接口实现类:MethodInterceptor
- Class:字节码
final Producer producer=new Producer();
Producer proxy=(Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
*
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Float money=(Float)objects[0];
Object rtValue=null;
if(method.getName().equals("saleService")) {
rtValue = method.invoke(producer, money * 0.8f);
}
return rtValue;
}
});
proxy.saleService(10000f);
- 这里应该是把
厂家
的子类作为代理对象,父类指向子类对象,上转型,保证了只会调用父类里的方法。同接口约束方法的作用一样。因此需要厂家
不是最终类。 - 别的和用接口做代理对象没区别。
网友评论