静态代理设计模式+JDK动态代理模式
又双叒叕是程序汪2021-01-07 22:58:39
静态代理设计模式
也就是 将要学习SpringAOP的底层原理:
Aop带来的作用:扩展程序
关于代理设计模式:
什么是设计模式?怎么理解
设计模式:前任总结的一套解决特定问题的代码。
静态代理
静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象,这种场景用于个体商家比较少的情况,如果多的话代理类十分繁多、不易维护
代理设计模式 的优点:
- 保护真实对象
- 让真实对象职责更明确
- 扩展
静态代理设计模式的缺点:
当代理功能比较多时,代理类中的方法需要写很多
JDK动态代理模式
动态代理存在的意义:
解决静态代理需要频繁编写代理功能的缺点
分类:
JDK提供
cglib动态代理
JDK动态代理
1.和cglib动态代理对比
优点: jdk自带,不需要额外导入Java包
缺点:真实对象必须实现接口
利用的是反射机制,效率不高
实例项目:(网上借阅)
1. 什么是代理模式?
日常生活中我们经常会碰到代理模式,例如我们找房产中介帮我们介绍房子,找婚姻中介帮我们介绍对象,找保洁帮我们打理房间,找律师帮我们进行诉讼等。我们在无形中运用到了代理模式,却不知道它的存在。
2. 为什么要使用代理?
运用代理可以使我们的生活更加便利,有了代理,我们不需要自己去找房子,不需要自己去找对象,不需要自己去打理房间,不需要自己去诉讼。当然,你也可以选择一切都自己来干,但是存在前提条件,一是你是否都具备这样的资源和能力来做这些事情,二是你是否愿意花费这么多精力和时间来做这些事情。总之,代理模式使我们各专其事,我们可以将时间浪费在美好的事情上,而不用天天被一些琐事所羁绊。
3. 代理模式有哪些实现方法?
Java中的代理有静态代理和动态代理,下面我会分别用一个简单的例子来介绍一下静态代理和动态代理代码实现。
3.1 静态代理
代理接口:UserDao.java
1 public interface UserDao {
2
3 void save();
4
5 }
目标对象:UserDaoImpl.java
1 public class UserDaoImpl implements UserDao {
2
3 @Override
4 public void save() {
5 System.out.println("正在保存用户...");
6 }
7
8 }
代理对象:TransactionHandler.java
1 public class TransactionHandler implements UserDao {
2
3 //目标代理对象
4 private UserDaoImpl target;
5
6 //构造代理对象时传入目标对象
7 public TransactionHandler(UserDaoImpl target) {
8 this.target = target;
9 }
10
11 @Override
12 public void save() {
13 //调用目标方法前的处理
14 System.out.println("开启事务控制...");
15 //调用目标对象的方法
16 target.save();
17 //调用目标方法后的处理
18 System.out.println("关闭事务控制...");
19 }
20
21 }
测试类:Main.java
1 public class Main {
2
3 public static void main(String[] args) {
4
5 //新建目标对象
6 UserDaoImpl target = new UserDaoImpl();
7
8 //创建代理对象, 并使用接口对其进行引用
9 UserDao userDao = new TransactionHandler(target);
10
11 //针对接口进行调用
12 userDao.save();
13
14 }
15
16 }
测试结果:
总结:
总的来说静态代理实现简单也容易理解,但是静态代理不能使一个代理类反复作用于多个目标对象,代理对象直接持有目标对象的引用,这导致代理对象和目标对象类型紧密耦合了在一起。如果UserDao接口下还有另一个实现类也需要进行事务控制,那么就要重新写一个代理类,这样就会产生许多重复的模版代码,不能达到代码复用的目的。而动态代理就可以很好的解决这样的问题。
3.2 动态代理
代理接口:UserDao.java
1 public interface UserDao {
2
3 void save();
4
5 }
目标对象:UserDaoImpl.java
1 public class UserDaoImpl implements UserDao {
2
3 @Override
4 public void save() {
5 System.out.println("保存用户信息...");
6 }
7
8 }
代理对象:TransactionHandler.java
1 public class TransactionHandler implements InvocationHandler {
2
3 //需要代理的目标对象
4 //这里设计为可以为任意对象添加事务控制, 所以将目标对象声明为Object
5 private Object target;
6
7 //构造TransactionHandler时传入目标对象
8 public TransactionHandler(Object target) {
9 this.target = target;
10 }
11
12 @Override
13 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
14 //调用目标方法前的处理
15 System.out.println("开启事务控制...");
16 //调用目标对象的方法
17 Object result = method.invoke(target, args);
18 //调用目标方法后的处理
19 System.out.println("关闭事务控制...");
20 //放回方法调用结果
21 return result;
22 }
23
24 }
测试类:Main.java
1 public class Main {
2
3 public static void main(String[] args) {
4
5 //新建目标对象
6 Object target = new UserDaoImpl();
7
8 //创建事务处理器
9 TransactionHandler handler = new TransactionHandler(target);
10
11 //生成代理类并使用接口对其进行引用
12 UserDao userDao = (UserDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),
13 target.getClass().getInterfaces(),
14 handler);
15 //针对接口进行方法调用
16 userDao.save();
17
18 }
19
20 }
测试结果:
总结:
之前我们发现了静态代理会产生许多重复代码,不能很好的进行代码复用,而动态代理能够很好的解决这个问题,代理类TransactionHandler实现了InvocationHandler接口,并且它持有的目标对象类型是Object,因此事务控制代理类TransactionHandler能够代理任意的对象,为任意的对象添加事务控制的逻辑。因此动态代理才真正的将代码中横向切面的逻辑剥离了出来,起到代码复用的目的。但是动态代理也有缺点,一是它的实现比静态代理更加复杂也不好理解;二是它存在一定的限制,例如它要求需要代理的对象必须实现了某个接口;三是它不够灵活,动态代理会为接口中的声明的所有方法添加上相同的代理逻辑。当然,这只是JDK动态代理所存在的一些缺陷,动态代理还有另外的实现如使用CGLIB库,在本文不做介绍,读者可以自行去了解。