设计模式系列文章:
1、设计模式之工厂模式
2、设计模式之单例模式
3、设计模式之代理模式
4、设计模式之外观模式(即门面模式)
5、设计模式之策略模式
6、设计模式之责任链模式
7、设计模式之观察者模式
8、设计模式之建造者模式
设计模式是一套反复使用的、多数人知晓的、经过分类编目的、代码设计经验总结。使用设计模式为了提高代码的可重用性,让代码更容易被他人理解,保证代码的可靠性。
代理模式:
For example :比如某歌星知名度非常高,很多单位都想请他去唱歌,但是呢,总不能他又要唱歌又要给自己接活吧,一般的都会雇佣一个经济人,这里的经济人他就是一个代理。如果有人想请该歌星去唱歌,那么需要直接联系的人是歌星的经济人,而不是直接找歌星,找到该经纪人以后谈好价钱,然后歌星再来唱歌,唱完歌以后,可能还需要与经纪人之间进行一些后续事物的处理。
一、代理模式的定义
为其他对象提供一种代理以控制对这个对象的访问
如果业务需求增加,则需要改动大量的代码,而使用代理对象起到中介作用,可以增加额外的服务
二、静态代理
1、创建接口Person以及被被代理类Singer
2、创建代理类Agent,并在Agent中聚合Singer
在我们使用静态代理的时候,每一个代理类只能为一个接口提供服务,这这样一来在程序开发中会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外,其他的操作都是相同的,这样就会造成过多的重复代码;
为了解决上述问题,我们使用一个代理类来完成所有的代理功能,而这就需要引入动态代理;
三、JDK动态代理
相比于Cjlib动态代理,jdk动态代理是针对实现了接口的类进行代理,而Cglib动态代理是针对类进行代理
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1) java.lang.reflect.InvocationHandler:该接口中仅定义了一个方法
public Object invoke(Object obj,Method method,Object[] args)
参数:
obj一般是指代理类;
method是被代理的方法;
args为该方法的参数数组。
这个抽象方法在代理类中动态实现。
(2)java.lang.reflect.Proxy:该类即为动态代理类
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,
InvocationHandler h)
返回代理类的一个实例,返回后的代理类可以当做被代理类使用
(可使用被代理类的在接口中声明过的方法)
jdk动态代理的使用步骤:
1.创建被代理的类以及接口
2.创建一个实现InvocationHandler接口的类,它必须实现invoke方法
3.调用Proxy的静态方法,创建一个代理类
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
4.通过代理调用方法
代码示例:
package com.tong.Proxy;
/**
* @describe 抽象接口
* @author tong
* @version 1.0 2017-11-11
*/
public interface Person {
public void sing();
}
package com.tong.Proxy;
/**
* @describe Person接口的具体实现 歌手Singer
* @author tong
* @version 1.0 2017-11-11
*/
public class Singer implements Person {
@Override
public void sing() {
System.out.println("********************歌手:我正在唱歌***********************");
}
}
package com.tong.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @describe 使用JDK动态代理
* @author tong
* @version 1.0 2017-11-11
*/
public class AgencyHandler implements InvocationHandler {
private Object target;
public AgencyHandler(Object target) {
super();
this.target = target;
}
/**
* 参数:
* proxy 被代理对象
* method 被代理对象方法
* args 方法的参数
* 返回值:
* Object 方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("******************演唱会以前:经纪人与合作商谈好价钱并签订合同***********************");
method.invoke(target);
System.out.println("******************演唱会以后:合作商按照合同把钱支付给经纪人***********************");
return null;
}
}
package com.tong.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args){
Singer singer = new Singer();
Class cls = singer.getClass();
InvocationHandler h = new AgencyHandler(singer);
// 使用Proxy类newProxyInstance方法动态创建代理类
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
//输出生成的代理类的类名,默认类名一般是$Proxy0,$Proxy1、$Proxy2等等
System.out.println(Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h).getClass());
Person p = (Person) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
p.sing();
}
}
运行结果:
class com.sun.proxy.$Proxy0
******************演唱会以前:经纪人与合作商谈好价钱并签订合同***********************
********************歌手:我正在唱歌***********************
******************演唱会以后:合作商按照合同把钱支付给经纪人***********************
小结:
使用JDK动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。
如果项目中有些类没有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口,通过cglib可以解决该问题。
三、Cglib动态代理
CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码。
使用cglib完成动态代理,大概的原理是:cglib继承被代理的类,重写方法,织入通知,动态生成字节码并运行,因为是继承所以final类是没有办法动态代理的。具体实现如下:
1、配置maven,安装Cglib
2、实现 MethodInterceptor方法代理接口,创建代理类
3、最后通过动态代理类对象进行方法调用。
小结:
使用cglib可以实现动态代理,即使被代理的类没有实现接口,但被代理的类必须不是final类。