一、概述
代理模式(Proxy Pattern),简单来说就是一个类代表另一个类的功能,属于结构型设计模式。主要意图是是为一个对象提供一种代理来控制对这个对象的访问。
这样做有一个好处就是:原对象可以只保留核心业务,其他的功能实现,可以放到代理对象中去,确保原对象不会被污染。
举个简单的例子:如果一位明星开演唱会,原对象就是唱歌的这位明星,但是他的经纪人(代理对象)来安排这场演唱会的所有工作,只是其中唱歌环节由这位明星来做而已。那么想邀请明星开演唱会,那么只需要联系他的经纪人即可。这就是一个简单代理。
二、三种代理模式
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类
接口
public interface Sport {
void run();
}
实现类
public class DoSport implements Sport {
@Override
public void run() {
System.out.println("跑步中。。。。。。。。");
}
}
代理对象
public class DoSportProxy implements Sport {
private Sport sport;
public DoSportProxy(Sport sport) {
this.sport = sport;
}
@Override
public void run() {
System.out.println("啦啦啦,我是跑步的小行家");
sport.run();
}
}
调用
System.out.println("===========静态代理============");
DoSport doSport = new DoSport();
DoSportProxy sportProxy = new DoSportProxy(doSport);
sportProxy.run();
结果
总结
优点是可以在不修改目标原对象的情况下,对原对象的功能进行拓展。
缺点是接口添加方法,代理对象和原对象都要进行修改。
动态代理
特点:
- 1.代理对象不需要实现接口,原对象要实现接口
- 2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
- 3.动态代理也叫做:JDK代理,接口代理。
接口和接口的实现对象还采用静态代理中的即可,我们只需对代理对象进行修改
代理对象
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("跑步准备,系鞋带");
Object result = method.invoke(object, args);
System.out.println("跑步完成,拨打120");
return result;
}
}
测试
// 动态代理
System.out.println("===========动态代理============");
Sport sport = new DoSport();
Sport proxySport = (Sport) Proxy.newProxyInstance(Sport.class.getClassLoader(),
new Class[]{Sport.class},new DynamicProxy(sport));
proxySport.run();
结果
总结
与静态代理相比,省去代理对象实现接口,但是原对象还需实现接口。
CGLIB代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
Cglib子类代理实现方法:
- 1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入Spring-core.jar即可.
- 2.引入功能包后,就可以在内存中动态构建子类
- 3.代理的类不能为final,否则报错
- 4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
原对象
public class Eat {
public void eatFoot() {
System.out.println("别吃辣么快。。。。");
}
}
CGLIB代理对象
第一种
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy() {
}
public CglibProxy(Object target) {
this.target = target;
}
public Object getInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
try {
long beginTime = System.currentTimeMillis();
System.out.println("方法的名称:" + method.getName());
Object object = method.invoke(target, objects);
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
return object;
} catch (Exception e) {
System.out.println("噎死的原因: " + e.getMessage());
}
return null;
}
}
第二种
public class CglibEat implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开饭啦,同志萌。。。。");
return methodProxy.invokeSuper(o, objects);
}
}
调用
System.out.println("===========Cglib代理============");
Eat eat = new Eat();
Eat eatProxy = (Eat) new CglibProxy(eat).getInstance();
eatProxy.eatFoot();
System.out.println("===========Cglib代理2============");
Eat cglibEat = (Eat) Enhancer.create(Eat.class, new CglibEat());
cglibEat.eatFoot();
结果
总结
与动态代理相比,原对象和代理对象都不需要实现接口,但是需要导入额外的架包。
常用代理模式是jdk动态代理和CGLIB代理,二者根据自己的喜爱进行选择使用。