循序渐进之Spring AOP(1) - 原理
来源:互联网 发布:购买特价机票的软件 编辑:程序博客网 时间:2024/06/06 10:01
AOP全称是Aspect Oriented Programing,通常译为面向切面编程。利用AOP可以对面向对象编程做很好的补充。
用生活中的改装车比喻,工厂用面向对象的方法制造好汽车后,车主往往有些个性化的想法,但是又不想对车进行大规模的拆卸、替换零件,这时可以买一些可替换的零件、装饰安装到汽车上,并且这些改装应该很容易拆卸,以避免验车时无法通过。
先看一个实际例子:有一个用户登录的方法,某一段时间内我们希望能够临时监控执行时间,但是又不想直接在方法上修改,用AOP方案实现如下。
UserService类
用sleep随机时间来模拟用户登录消耗的时间
import java.util.Random;public class UserService {public void login(String userName, String password) {try {Thread.sleep(new Random(47).nextInt(100));} catch (InterruptedException e) {}System.out.println("UserService: 用户" + userName + "登录成功");}}
PerformanceMonitorUserService类,Spring将把它当作UserService的替身(代理,Proxy)
import java.util.concurrent.TimeUnit;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class PerformanceMonitorUserService {@Around("execution(* login(..))")public void aroundLogin(ProceedingJoinPoint pjp) {String userName = pjp.getArgs()[0].toString();long begin = System.nanoTime();try {pjp.proceed();} catch (Throwable e) {e.printStackTrace();}long end = System.nanoTime();System.out.println("PerformanceMonitorUserService: 用户" + userName + "登录耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");}}
applicationContext.xml,放在src根目录
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><aop:aspectj-autoproxy /><bean id="userService" class="demo.aop.UserService" /><bean class="demo.aop.PerformanceMonitorUserService" /></beans>
需要添加的jar包
测试代码
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Client {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = (UserService)ctx.getBean("userService");userService.login("Tom", "123456");}}
UserService: 用户Tom登录成功PerformanceMonitorUserService: 用户Tom登录耗时71毫秒
这样就保持了UserService业务的纯粹性,避免非业务代码和业务代码混合在一起。如果希望取消时间监控,只需要删除applicationContext里的<bean class="demo.aop.PerformanceMonitorUserService" />即可。
Spring是如何做到的呢?底层的两大功臣是JDK的动态代理和CGLib动态代理技术。我们以JDK的动态代理技术来重现上面的过程
UserService接口(JDK动态代理只能为接口创建代理,所以先抽象了一个接口)
public interface UserService {void login(String userName, String password);}实现类
import java.util.Random;public class UserServiceImpl implements UserService {public void login(String userName, String password) {try {Thread.sleep(new Random(47).nextInt(100));} catch (InterruptedException e) {}System.out.println("UserService: 用户" + userName + "登录成功");}}代理类
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.util.concurrent.TimeUnit;public class PerformanceMonitorUserService implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long begin = System.currentTimeMillis();Object obj = method.invoke(target, args);long end = System.currentTimeMillis();System.out.println("PerformanceMonitorUserService: 用户" + args[0] + "登录耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");return obj;}private Object target;public PerformanceMonitorUserService(Object target) {this.target = target;}}测试代码
import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {UserService target = new UserServiceImpl();PerformanceMonitorUserService handler = new PerformanceMonitorUserService(target);UserService proxy = (UserService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);proxy.login("Tom", "123456");}}从上面的代码可以看出,AOP的原理就是创建代理,在运行时我们开发的业务逻辑类已经被替换成添加了增强代码的代理类,而Spring帮我们省略了这些繁琐和重复的步骤。
0 0
- 循序渐进之Spring AOP(1) - 原理
- 循序渐进之Spring AOP(2) - 基本概念
- 循序渐进之Spring AOP(3) - 配置代理
- 循序渐进之Spring AOP(4) - Introduction
- 循序渐进之Spring AOP(5) - 创建切面
- 循序渐进之Spring AOP(6) - 使用@Aspect注解
- Spring AOP系列之AOP原理介绍
- Spring之AOP原理详解
- Spring框架中,AOP编程循序渐进-笔记
- 2、spring之aop 原理和应用
- Spring 之AOP技术原理剖析
- Spring AOP之动态代理原理解析
- spring学习日志之五 AOP原理
- Spring AOP之动态代理原理解析
- Spring AOP & AspectJ之原理探析
- spring源码分析之——spring aop原理
- spring源码分析之——spring aop原理
- spring框架之AOP-1
- Tsinsen A1128 计算器的改良
- 今天我要开始写博客啦
- LSTM 网络详解
- android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a vi
- 《LeetBook》leetcode题解(3):Longest Substring Without Repeating Characters[M]——哈希判断重复
- 循序渐进之Spring AOP(1) - 原理
- iOS安全–在非越狱平台进行越狱开发(附分析流程)
- 如何阻止移动设备(手机,pad)浏览器双击放大网页?
- 【九度】题目1054:字符串内排序
- 第5周项目4-长方柱类
- android.view.GLES20RecordingCanvas.drawBitmap异常
- codevs2370小机房的树
- 使用Classie.js让添加、删除和检查类更容易
- P值已经被废,学的东西有多少是真的?