代理设计模式
代理设计模式的作用
代理模式(Proxy Pattern)是指建立某一个对象的代理对象,并且由代理对象控制对原对象的引用。可以在目标对象的基础上,增强额外的功能操作,即扩展目标对象的功能.
- 需求
项目经理:有一天早上项目经理突然对小张说,小张啊现在给你分配一个需求,之前小王开发的那个接口的功能还不够完善你看着给他完善一下。。。
小张:好的经理,突然小张心想他妈的我去改他的代码万一改出问题了咋办,那岂不是给自己增加工作量,那有没有一种方法可以在不改小王代码的前提下完成本次需求也了。。。突然小张灵机一动代理模式好像可以解决这个问题
下面小张就开始写代码了
- 首先
小王写了一个 UserService 接口
public interface UserService {
/**
* 吃饭
*/
void eat();
void run();
}
小王写了一个 UserService 实现类 UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void eat() {
System.out.println("开始吃饭了哦");
}
@Override
public void run() {
System.out.println("跑步中");
}
}
- 小王接到的任务是在不动原来代码的前提下完成现有的功能
上文说到小王想到可以使用动态代理完成现有的需求,鉴于本次更改的量比较小,所以首先使用静态代理完成本次需求
1、创建静态 Proxy 类
public class UserProxy {
private UserService target;
public UserProxy(UserService target) {
this.target = target;
}
public void enhanceEat() {
before();
target.eat();
after();
}
// 前置增强
public void before() {
System.out.println("执行 eat 方法之前 需要先洗手");
}
// 后置增强
public void after() {
System.out.println("执行 eat 方法之后 需要先洗手");
}
}
- 2、静态代理测试
public class UserProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserProxy userProxy = new UserProxy(userService);
userProxy.enhanceEat();
}
}
3、小王心想如何后面经理让我改很多个接口了,那岂不要写很多个代理类,妈的这也太麻烦了吧,要不试一下动态代理
4、编写代理类 UserHandler 需要实现 InvocationHandler 接口并重写 invoke 接口进行动态的方法增强
public class UserHandler implements InvocationHandler {
private Object target;
public UserHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增强");
Object res = method.invoke(target , args);
System.out.println("后置增强");
return res;
}
}
5、测试动态代理
public class UserProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
UserHandler userHandler = new UserHandler(userService);
UserService o = (UserService)Proxy.newProxyInstance(loader, interfaces, userHandler);
o.run();
}
}
6、CGLIB 实现动态代理
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object newInstance() {
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置增强");
method.invoke(target , args);
System.out.println("后置增强");
return null;
}
}
7、CGLIB 动态代理测试
public class ProxyFactoryTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService userService1 = (UserService)new ProxyFactory(userService).newInstance();
userService1.run();
}
}
静态代理的优劣势
- 优点
实现简单不侵入原来的代码 - 缺点
1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2、代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
动态代理的优劣势
- 缺点
1、动态代理基于 Java 反射机制实现, 必须要实现了接口的业务类才能用这种方法生成代理对象 - 优点
1、不用创建代理类
2、可以给不同的目标随时创建代理