赞
踩
一、AOP的基本概念
AOP先是一种思想,后是一种技术。
AOP:面向切面编程,是将那些与业务无关(比如有事务处理,日志管理,权限控制等),但要为业务模块共同调用的逻辑封装成一个可重用的模块,这个模块被称为切面,便于减少系统的重复代码,降低模块间的耦合度,有利于未来的可拓展性和可维护性。如下图所示:
Target:所谓target就是横切新代码的对象
Joinpoint:连接点,就是在Target上具体的执行点,与Pointcut匹配
Aspect:切面,其中包装着Advice和Pointcut,是通过Bean注册的基本单位
Pointcut:切入点,与Joinpoint对应,定义了切面逻辑的执行地点
Advice:是具体的切入逻辑,切面完成的工作包含在Advice中
Weaving:织入,把切面加入到对象中,并创建出代理对象的过程
织入时期:(如下表所示)
时期 | 理解 |
编译期 | 切面在目标类编译时被织入,需要特殊的编译器,Aspect的织入编译器以这种方式织入切面 |
类加载期 | 切面在目标类加载到JVM时被织入,这种方式需要特殊的类加载器(ClassLoader),可以在目标类引入应用之前增强目标类的字节码 |
运行期 | 切面在应用的某个时期被织入,在织入切面时,AOP容器会为目标对象动态创建一个代理对象 |
AOP的通知类型:
1.前置通知:实现MethodBeforeAdvice接口,在目标方法调用前,执行通知。
2.环绕通知:实现MethodInterceptor接口,是一个包围目标方法的通知。此通知可以在方法调用前后完成自定义的行为。
3.后置通知:实现AfterReturningAdvice接口,在目标方法调用后,执行通知,如果方法跑出来异常,那么不执行通知。
4.异常通知:实现ThrowsAdvice接口,在方法抛出异常的时候,执行通知。
二、Spring的AOP基于动态代理实现
1. 首先,如果被代理的对象,已经实现了某个接口,那么AOP会使用反射,通过接口的方式来创建代理对象。jdk实现动态代理需要两个组件,一个为InvocationHandler接口,需要编写一个类去实现这个接口,然后重写invoke()方法;
另一个为Proxy类,我们可以通过这个类的newProxyInstance()方法,返回一个代理对象,生成的代理类实现了原来类的所有接口,然后对这些接口进行代理,通过代理对象调用这些方法,底层通过反射来调用我们实现的invoke()方法。
2. 如果被代理的对象没有实现某个接口,无法通过反射去进行动态代理,这个时候AOP要使用Cglib,基于继承的方式生成一个被代理对象的子类来作为代理。也就是说Cglib要实现一个MethodInteceptor,方法调用会被转发到该类的intercept()方法,然后在需要使用目标对象的时候,通过Cglib动态代理来获取代理对象。
三、两种动态代理的区别
jdk方式:采用反射的方式,只能对实现接口的类生成代理,加载速度快,执行效率低。
Cglib方式:通过字节码形式实现,针对类实现代理,加载速度满,但执行效率高。
四、AOP的作用
AOP采用横向抽取机制,取代了传统纵向继承机制的重复性代码,应用主要体现在事务处理,日志管理,权限控制,异常处理等方面。
主要作用:分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。
总结的来说就是AOP主要是保证开发者在不修改源代码的前提下,为系统中的业务逻辑组件添加某种通用功能。
五、代码实现
- @Aspect // 面向切面
- @Component // UserAOP 注解为Bean
- public class UserAOP {
- @Pointcut("execution(* com.yjy.service.impl.*.*(..))")
- public void pointcut() {
- }
-
- @Before("pointcut()")
- public void beforeAdvice(JoinPoint point) {
- System.out.println("前置增强:" + point.getSignature().getName() + "方法。");
- }
-
- @AfterReturning(value = "pointcut()", returning = "obj")
- public Object afterReturnAdvice(Object obj) throws Throwable {
- // 被增强方法的返回结果
- System.out.println("基于Spring AOP的后置返回增强处理.....结果:" + obj);
- return obj;
- }
-
- @After("pointcut()")
- public void afterAdvice(JoinPoint point) {
- System.out.println("基于Spring AOP的最终增强处理.....方法:" + point.getSignature().getName());
- }
-
- @Around("pointcut()")
- public Object aoundAdvice(ProceedingJoinPoint jp) {
- System.out.println("环绕增强:" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法,参数:" + Arrays.toString(jp.getArgs()));
- Object res = null;
- try {
- res = jp.proceed();//调用目标方法 返回目标方法的返回结果
- } catch (Throwable e) {
- System.out.println("环绕增强 catch:" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法,参数:" + Arrays.toString(jp.getArgs()) + "发生异常:" + e.getMessage());
- } finally {
- System.out.println("基于Spring AOP的环绕增强中finally处理.....");
- }
- return res;
- }
-
- @AfterThrowing(value = "pointcut()", throwing = "e")
- public void afterThrowAdvice(JoinPoint p, RuntimeException e) {
- // System.out.println("基于Spring AOP的异常返回增强处理.....");
- System.out.println("异常增强:" + p.getSignature().getName() + "发生了异常" + e.getMessage());
-
-
- }
-
- }
- public interface UserService {
- void queryAll();
- int addUser();
-
- }
- @Service("userServiceImpl")
- public class UserServiceImpl implements UserService {
- @Override
- public void queryAll() {
- System.out.println("执行了查询所有的业务");
- // 抛出异常
- // throw new RuntimeException("没事..测试");
- }
-
- @Override
- public int addUser() {
- System.out.println("执行了 新增");
- // if (true) {
- // throw new RuntimeException("没事..测试");
- // }
- return 1;
- }
- }
- public class TestAop {
-
- @Test
- public void TestAop() {
- ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
-
- UserService userService = (UserService) ac.getBean("userServiceImpl");
-
- userService.addUser();
- }
- }
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。