参考资料1:http://c.biancheng.net/design_pattern/
参考资料2:https://refactoringguru.cn/design-patterns/catalog
代理模式是Java常见的设计模式之一。
代理模式是指不直接调用实际对象,而是通过调用代理,来间接的调用实际的对象。
为什么要采用这种间接的形式来调用对象呢?
场景①:不想直接访问
实际的对象;
场景②:对实际的对象的访问存在困难
;
场景③:有需求需要将封装对象访问/操作的成员方法进行逻辑增强,而不修改原方法
;
在现实生活中,这种情形非常的常见,比如请一个律师代理来打官司。
代理模式可以有 2 种实现的方式:
一种是静态代理
,另一种是各大框架都喜欢的动态代理
。
还有一种类似静态代理的装饰者模式
。
现有 User 实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class User { private int id; private String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
|
DAO封装数据访问思想:用来封装对实体类 User 类的访问/操作。
UserDao 接口:
1 2 3 4 5 6
| public interface UserDao { void add(String id, String id2) void delete(); void update(); void select(); }
|
UserDaoImpl 实现类:
1 2 3 4 5 6 7 8 9 10 11 12
| public class UserDaoImpl implements UserDao { @Override public void add(String id, String id2) { System.out.println("add:" + id + "," + id2); } @Override public void delete() { System.out.println("delete"); } @Override public void update() { System.out.println("update"); } @Override public void select() { System.out.println("select"); } }
|
需求:通过 静态代理、装饰者、动态代理模式分别 增强 add() 方法的逻辑功能
。
动态代理是通过反射来实现的,借助Java自带的 java.lang.reflect.Proxy
通过固定的规则生成。
动态代理本质就是通过反射
来生成的一个代理。
在Java中 java.lang.reflect 包下提供了一个 Proxy 类
和 InvocationHandler 接口
,通过使用这个类和接口就可以生成动态代理对象,Proxy类中的方法创建动态代理对象。
JDK提供的代理只能针对接口做代理,有更强大的代理cglib
:
一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
1.1 实现步骤
步骤:——基于接口的方法增强
① 编写一个代理类的接口
② 实现一个真正的代理类,实现该接口
③ 创建一个动态的代理类,实现 InvocationHandler 接口
,并重写该 invoke()
方法
④ 在测试类中调用 Proxy.newProxyInstance()
方法生成动态代理对象
优化:③④可合并为实现了对应接口匿名内部类
替代。
即 在调用该动态代理对象的成员方法时,是 invoke 增强的方法执行。
1.2 逻辑图 & 源码示例
顶部。
Proxy.newProxyInstance() 方法的参数解释:
1 2 3 4 5 6 7 8 9 10 11
|
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
|
InvocationHandler 接口的 invoke 方法参数解释:
1 2 3 4 5 6 7 8 9
|
@Override public Object invoke(Object proxy, Method method, Object[] args);
|
匿名内部类直接测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import org.springframework.cglib.proxy.Proxy;
public class TestProxy { public static void main(String[] args) { UserDao userDao = new UserDaoImpl(); UserDao p = (UserDao) Proxy.newProxyInstance( userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), (proxy, method, argss) -> { String methodName = method.getName(); for (int i = 0; i < argss.length; i++) { argss[i] = "88"; } Object result; if ("add".equals(methodName)) { System.out.println("权限校验"); result = method.invoke(userDao, argss); System.out.println("日志记录"); } else { result = method.invoke(userDao, argss); } return result; }); p.add("22", "33"); p.delete(); } }
|
1.3 动态代理设计模式 - 优缺
优点:不需要重写接口中的所有方法,耦合度更低
。
缺点:没有,动态代理就是这么任性,这条gai最靓的仔本仔!