Version: Next
代理模式
为什么要学习代理模式?因为这是Spring AOP的底层
SpringAOP 必问
SpringMVC 必问
分类
- 静态代理
- 动态代理
- UML类图
1. 静态代理
角色分析:
- 抽象角色Subject:一般会使用接口或者抽象类
- 真实角色RealSubject:被代理的角色
- 代理角色Proxy:代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象,用代理对象做一些操作的人
新建一个Maven模块spring-08-proxy
类
public class Landlord implements com.bsx.client.demo01.interfaces.Landlord {public void rent() {System.out.println("房东要出租房子");}}public class Proxy implements com.bsx.client.demo01.interfaces.Landlord {private Landlord landlord;public Proxy() {}public Proxy(Landlord landlord) {this.landlord = landlord;}//加一些方法,体现代理对象可以对源对象做增强public void rent() {this.landlord.rent();checkHouse();collectFee();}public void checkHouse(){System.out.println("中介代理带你看房");}public void collectFee(){System.out.println("收中介费");}}
public class Client {public static void main(String[] args) {//为了让代理对象有东西可代理,创建一个真实房东//代理可以对被代理对象做增强Landlord landlord = new Landlord();Proxy proxy = new Proxy(landlord);proxy.rent();}}接口
/**** 房东接口*/public interface Landlord {public void rent();}
1.1 应用实例
新建包demo02
接口
public interface UserService {public void add();public void delete();public void update();public void query();}实现类
public class UserServiceImpl implements UserService{public void add() {System.out.println("增加了一个用户");}public void delete() {System.out.println("删除了一个用户");}public void update() {System.out.println("更新了一个用户");}public void query() {System.out.println("查询了一个用户");}}客户端
public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();userService.add();}}
假如头头要求我们在方法调用前输出一条日志,那么输出日志的代码在每个方法都得添加 ↓
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("日志:使用了add方法");
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("日志:使用了add方法");
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("日志:使用了add方法");
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("日志:使用了add方法");
System.out.println("查询了一个用户");
}
}
这显然是不好的写法,依据开闭原则,我们可以用代理在不改变源代码的情况下,扩展出日志功能
代理类
public class UserServiceProxy implements UserService {private UserServiceImpl userService;public void setUserService(UserServiceImpl userService) {this.userService = userService;}public void add() {log("add");userService.add();}public void delete() {log("delete");userService.delete();}public void update() {log("update");userService.update();}public void query() {log("query");userService.query();}//日志方法public void log(String message) {System.out.println("[Debug] 使用了" + message + "方法");}}客户端
public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy userServiceProxy = new UserServiceProxy();userServiceProxy.setUserService(userService);userServiceProxy.add();}}
2. 动态代理
- 动态代理类是动态生成的,不是直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK动态代理
- 基于类:cglib
- Java字节码实现:javassist
2.1 JDK动态代理
需要了解两个东西:Proxy
类、InvocationHandler
接口
InvocationHandler
接口 —— 用来指定如何增强对象- 方法(只有一个)
invoke(Object proxy, 方法 method, Object[] args)
- proxy:你要代理谁
- method:代理这个类里的哪一个方法
- args:给代理方法里传的参数
- 方法(只有一个)
Proxy
类 (反射) —— 用来生成代理对象实例Proxy.getProxyClass(Xxx.class.getClassLoader(), Xxx.class)
,返回代理类Proxy.getInvocationHandler(Object proxy)
Proxy.newProxyInstance(ClassLoader loader, 类[] interfaces, InvocationHandler h)
- interfaces:类和代理类实现的共同接口
- invocationHandler:new 一个扔进去
真实类
/**** 真实房东*/public class Landlord implements LandlordInterface {public void rent() {System.out.println("房东要出租房子");}}接口
/**** 房东接口*/public interface LandlordInterface {public void rent();}动态代理类
public class DynamicProxyLandlord implements InvocationHandler {//1.真实对象private Landlord landlord;/**** 增强对象* @param proxy* @param method 要优化/拦截的方法* @param args* @return* @throws Throwable*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {EnhanceLogPre();//真实对象landlord调用方法Object result = method.invoke(landlord, args);EnhanceLogSuf();return result;}/**** 通过Proxy获取动态代理的对象* - 第二个参数用来实现和被代理对象一样的接口* - 第三个参数用来指定一个InvocationHandler,指定如何增强对象*/public Object getProxyInstance() {return Proxy.newProxyInstance(landlord.getClass().getClassLoader(),landlord.getClass().getInterfaces(), this);}public void setLandlord(Landlord landlord) {this.landlord = landlord;}private void EnhanceLogPre() {System.out.println("[info] 动态代理日志,增强方法执行,前");}private void EnhanceLogSuf() {System.out.println("[info] 动态代理日志,增强方法执行,后");}}客户端
public class Client {public static void main(String[] args) {//1.创建真实对象Landlord landlord = new Landlord();//2.创建用来动态生成代理类的 类的对象DynamicProxyLandlord dynamicProxyLandlord = new DynamicProxyLandlord();//3.把真实对象扔进去dynamicProxyLandlord.setLandlord(landlord);//4.获取代理对象,强转成接口LandlordInterface proxyLandlord =(LandlordInterface) dynamicProxyLandlord.getProxyInstance();//5.通过代理对象执行方法proxyLandlord.rent();}}