Spring AOP的实现原理以及应用场景。
AOP 应用场景
- 记录日志;
- 监控方法运行时间(监控性能);
- 权限控制;
- 缓存优化(第一次调用查询数据库,将查询结果放入内存对象,第二次调用则直接从内存对象返回,不需要查询数据库);
- 事务管理(调用方法前开启事务,调用方法后提交关闭事务);
AOP 实现原理
Spring 中 AOP 的两种实现方式:
- JDK 动态代理;
- Cglib 动态代理;
JDK 动态代理
-
引入依赖,有 Spring、单元测试和日志管理;
1<dependencies> 2 <!-- Spring --> 3 <dependency> 4 <groupId>org.springframework</groupId> 5 <artifactId>spring-context</artifactId> 6 </dependency> 7 8 <!-- 单元测试 --> 9 <dependency> 10 <groupId>junit</groupId> 11 <artifactId>junit</artifactId> 12 <scope>test</scope> 13 </dependency> 14 <!-- 日志 --> 15 <dependency> 16 <groupId>org.slf4j</groupId> 17 <artifactId>slf4j-log4j12</artifactId> 18 </dependency> 19</dependencies>
-
UserDao 接口
1public interface UserDao { 2 public void saveUser(); 3} 4
-
UserDao 实现类
1public class UserDaoImpl implements UserDao { 2 3 @Override 4 public void saveUser() { 5 System.out.println("持久层:用户保存"); 6 } 7}
-
动态代理
1@Test 2 public void test1() { 3 4 final UserDao userDao = new UserDaoImpl(); 5 // newProxyInstance的三个参数解释: 6 // 参数1:代理类的类加载器,同目标类的类加载器 7 // 参数2:代理类要实现的接口列表,同目标类实现的接口列表 8 // 参数3:回调,是一个InvocationHandler接口的实现对象,当调用代理对象的方法时,执行的是回调中的invoke方法 9 //proxy为代理对象 10 UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), 11 userDao.getClass().getInterfaces(), new InvocationHandler() { 12 13 @Override 14 // 参数proxy:被代理的对象 15 // 参数method:执行的方法,代理对象执行哪个方法,method就是哪个方法 16 // 参数args:执行方法的参数 17 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 18 System.out.println("记录日志"); 19 Object result = method.invoke(userDao, args); 20 return result; 21 } 22 }); 23 //代理对象执行方法 24 proxy.saveUser(); 25 }
-
结果,在没有修改原有类的代码的情况下,对原有类的
Cglib 动态代理
在实际开发中,可能需要对没有实现接口的类增强,用 JDK 动态代理的方式就没法实现。采用 Cglib 动态代理可以对没有实现接口的类产生代理,实际上是生成了目标类的子类来增强。
首先,需要导入 Cglib 所需的 jar 包。提示:spring 已经集成了 cglib,我们已经导入了 spring 包,所以不需要再导入其它包了。
-
创建 LinkManDao 类,没有实现任何接口
1public class LinkManDao { 2 public void save(){ 3 System.out.println("持久层:联系人保存...."); 4 } 5}
-
动态代理
1@Test 2 public void test2() { 3 final LinkManDao linkManDao = new LinkManDao(); 4 // 创建cglib核心对象 5 Enhancer enhancer = new Enhancer(); 6 // 设置父类 7 enhancer.setSuperclass(linkManDao.getClass()); 8 // 设置回调 9 enhancer.setCallback(new MethodInterceptor() { 10 /** 11 * 当你调用目标方法时,实质上是调用该方法 12 * intercept四个参数: 13 * proxy:代理对象 14 * method:目标方法 15 * args:目标方法的形参 16 * methodProxy:代理方法 17 */ 18 @Override 19 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) 20 throws Throwable { 21 System.out.println("记录日志"); 22 Object result = method.invoke(linkManDao, args); 23 return result; 24 } 25 }); 26 // 创建代理对象 27 LinkManDao proxy = (LinkManDao) enhancer.create(); 28 proxy.save(); 29 }
-
结果