一.概述

AOP:(Aspect Oriented Programming)即:面向切面编程。把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

二.术语

Joinpoint(连接点):可以被代理增强的方法,即被spring拦截到的点,spring中点即方法,因为spring只支持方法类型的连接点;

Pointcut(切入点):需要或已经被增强的Joinpoint;

Advice(通知):拦截到Joinpoint之后要做的事情即为通知,即要增强的方法;
     通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Target(目标对象):代理的目标对象,或被增强的对象,或Pointcut所在对象;

Proxy(代理对象):对目标对象进行增强后产生的对象;一个类被AOP织入增强后,就产生一个结果代理类。

Weaver(织入):把增强应用到目标对象来创建新的代理对象的过程。将通知应用到切点的过程,称为Weaver;spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

Aspect(切面):切点+通知

Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。

三.案例演示:xml--抽取UserServiceImpl中的公共代码

1.导包-4+2/aspects/aop/aopalliance/aspectj.weaver/test

2.建立工程结构:
     huguangqin.com.cnblogs.advice
     huguangqin.com.cnblogs.service
     huguangqin.com.cnblogs.service.serviceImpl
     huguangqin.com.cnblogs.test

3.准备目标对象--要增强的方法所在类UserServiceImpl
    

  1. 1 package huguangqin.com.cnblogs.service.serviceImpl;
  2. 2 import huguangqin.com.cnblogs.service.UserService;
  3. 3 public class UserServiceImpl implements UserService {
  4. 4 @Override
  5. 5 public void save() {
  6. 6 System.out.println("客户保存了");
  7. 7 }
  8. 8
  9. 9 @Override
  10. 10 public void delete() {
  11. 11 System.out.println("客户删除了");
  12. 12 }
  13. 13
  14. 14 @Override
  15. 15 public void find() {
  16. 16 System.out.println("客户找到了");
  17. 17 }
  18. 18
  19. 19 @Override
  20. 20 public void update() {
  21. 21 System.out.println("客户更新了");
  22. 22 }
  23. 23 }
  24. 24

4
.准备通知--增强的方法myAdvice
    

  1. 1 package huguangqin.com.cnblogs.advice;
  2. 2 import org.aspectj.lang.ProceedingJoinPoint;
  3. 3 //通知类
  4. 4 public class MyAdvice {
  5. 5 // 前置
  6. 6 public void before() {
  7. 7 System.out.println("我是前置通知!");
  8. 8 }
  9. 9
  10. 10 // 环绕通知
  11. 11 /*
  12. 12 * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
  13. 13 * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
  14. 14 * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
  15. 15 */
  16. 16 public Object around(ProceedingJoinPoint pjp) throws Throwable {
  17. 17 System.out.println("我是环绕通知,前半部分!");
  18. 18 // 执行目标方法
  19. 19 Object proceed = pjp.proceed();
  20. 20 System.out.println("我是环绕通知,后半部分!");
  21. 21 return proceed;
  22. 22 }
  23. 23
  24. 24 // 后置 => 出现异常就不执行的后置通知
  25. 25 public void afterReturning() {
  26. 26 System.out.println("我是后置通知,出现异常就不执行的后置通知!");
  27. 27 }
  28. 28
  29. 29 // 最终通知 => 无论是否出现异常都执行的后置通知
  30. 30 public void after() {
  31. 31 System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
  32. 32 }
  33. 33
  34. 34 // 异常 => 出现异常才执行的通知
  35. 35 public void afterThrowing() {
  36. 36 System.out.println("我是异常通知,出现异常才执行的通知!");
  37. 37 }
  38. 38 }
  39. 39

5
.编写配置对象applicationContext.xml(位置在src下)
   

  1. 1 <?xml version="1.0" encoding="UTF-8"?>
  2. 2
  3. 3 <beans
  4. 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. 5 xmlns="http://www.springframework.org/schema/beans"
  6. 6 xmlns:context="http://www.springframework.org/schema/context"
  7. 7 xmlns:aop="http://www.springframework.org/schema/aop"
  8. 8 xsi:schemaLocation="http://www.springframework.org/schema/beans
  9. 9 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
  10. 10 http://www.springframework.org/schema/context
  11. 11 http://www.springframework.org/schema/context/spring-context-4.2.xsd
  12. 12 http://www.springframework.org/schema/aop
  13. 13 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
  14. 14
  15. 15 <!--配置目标对象 -->
  16. 16 <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
  17. 17
  18. 18 <!--配置通知对象 -->
  19. 19 <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
  20. 20
  21. 21 <!--将通知织入目标 -->
  22. 22 <!-- 切点表达式
  23. 23 public void huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl.save()
  24. 24 * huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..):
  25. 25 第一个*代表:返回值任意;
  26. 26 第二个*代表:包内所有以ServiceImpl结尾的类;
  27. 27 第三个*代表:类内所有方法
  28. 28 括号内..代表:任意参数
  29. 29 -->
  30. 30 <aop:config>
  31. 31 <!--配置切点 -->
  32. 32 <aop:pointcut expression="execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))" id="mypc"></aop:pointcut>
  33. 33 <!--配置切面 -->
  34. 34 <aop:aspect ref="myAdvice">
  35. 35 <!--前置通知 -->
  36. 36 <aop:before method="before" pointcut-ref="mypc" />
  37. 37 <!--环绕通知 -->
  38. 38 <aop:around method="around" pointcut-ref="mypc" />
  39. 39 <!--最终通知 :出现异常也执行 -->
  40. 40 <aop:after method="after" pointcut-ref="mypc" />
  41. 41 <!--异常通知 -->
  42. 42 <aop:after-throwing method="afterThrowing" pointcut-ref="mypc" />
  43. 43 <!--后置通知:出现异常不执行 -->
  44. 44 <aop:after-returning method="afterReturning" pointcut-ref="mypc" />
  45. 45 </aop:aspect>
  46. 46 </aop:config>
  47. 47 </beans>
  48. 48

6.测试
    

  1. 1 package huguangqin.com.cnblogs.test;
  2. 2 import javax.annotation.Resource;
  3. 3 import org.junit.Test;
  4. 4 import org.junit.runner.RunWith;
  5. 5 import org.springframework.test.context.ContextConfiguration;
  6. 6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  7. 7 import huguangqin.com.cnblogs.service.UserService;
  8. 8
  9. 9 @RunWith(SpringJUnit4ClassRunner.class)
  10. 10 @ContextConfiguration("classpath:applicationContext.xml")
  11. 11 public class Demo {
  12. 12 @Resource(name = "userService")
  13. 13 private UserService us;
  14. 14
  15. 15 @Test
  16. 16 public void save() {
  17. 17 us.save();
  18. 18 }
  19. 19 }
  20. 20

四.案例演示:注解模式
     与xml模式相比,需修改applicationContext.xml和MyAdvice类
     1.applicationContext.xml
   

  1. 1 <?xml version="1.0" encoding="UTF-8"?>
  2. 2
  3. 3 <beans
  4. 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. 5 xmlns="http://www.springframework.org/schema/beans"
  6. 6 xmlns:context="http://www.springframework.org/schema/context"
  7. 7 xmlns:aop="http://www.springframework.org/schema/aop"
  8. 8 xsi:schemaLocation="http://www.springframework.org/schema/beans
  9. 9 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
  10. 10 http://www.springframework.org/schema/context
  11. 11 http://www.springframework.org/schema/context/spring-context-4.2.xsd
  12. 12 http://www.springframework.org/schema/aop
  13. 13 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
  14. 14
  15. 15 <!--配置目标对象 -->
  16. 16 <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
  17. 17
  18. 18 <!--配置通知对象 -->
  19. 19 <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
  20. 20
  21. 21 <!--将通知织入目标 ,打开注解配置开关 -->
  22. 22 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  23. 23 </beans>
  24. 24

2.MyAdvice
   

  1. 1 package huguangqin.com.cnblogs.advice;
  2. 2
  3. 3 import org.aspectj.lang.ProceedingJoinPoint;
  4. 4 import org.aspectj.lang.annotation.After;
  5. 5 import org.aspectj.lang.annotation.AfterReturning;
  6. 6 import org.aspectj.lang.annotation.AfterThrowing;
  7. 7 import org.aspectj.lang.annotation.Around;
  8. 8 import org.aspectj.lang.annotation.Aspect;
  9. 9 import org.aspectj.lang.annotation.Before;
  10. 10
  11. 11 //通知类
  12. 12 @Aspect
  13. 13 public class MyAdvice {
  14. 14
  15. 15 // 前置
  16. 16 @Before("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
  17. 17 public void before() {
  18. 18 System.out.println("我是前置通知!");
  19. 19 }
  20. 20
  21. 21 // 环绕通知
  22. 22 /*
  23. 23 * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
  24. 24 * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
  25. 25 * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
  26. 26 */
  27. 27 @Around("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
  28. 28 public Object around(ProceedingJoinPoint pjp) throws Throwable {
  29. 29 System.out.println("我是环绕通知,前半部分!");
  30. 30 // 执行目标方法
  31. 31 Object proceed = pjp.proceed();
  32. 32 System.out.println("我是环绕通知,后半部分!");
  33. 33 return proceed;
  34. 34 }
  35. 35
  36. 36 // 后置 => 出现异常就不执行的后置通知
  37. 37 @AfterReturning("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
  38. 38 public void afterReturning() {
  39. 39 System.out.println("我是后置通知,出现异常就不执行的后置通知!");
  40. 40 }
  41. 41
  42. 42 // 最终通知 => 无论是否出现异常都执行的后置通知
  43. 43 @After("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
  44. 44 public void after() {
  45. 45 System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
  46. 46 }
  47. 47
  48. 48 // 异常 => 出现异常才执行的通知
  49. 49 @AfterThrowing("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
  50. 50 public void afterThrowing() {
  51. 51 System.out.println("我是异常通知,出现异常才执行的通知!");
  52. 52 }
  53. 53 }
  54. 54

四.动态代理回顾

1.原生动态代理--必需要一个接口,否则不能使用

a.编写接口
   

  1. 1 package huguangqin.com.cnblogs.serive;
  2. 2
  3. 3 public interface Service {
  4. 4 void find();
  5. 5 }
  6. 6

b.编写接口的实现类
   

  1. 1 package huguangqin.com.cnblogs.seriveImpl;
  2. 2
  3. 3 import huguangqin.com.cnblogs.serive.Service;
  4. 4
  5. 5 public class ServiceImpl implements Service {
  6. 6
  7. 7 @Override
  8. 8 public void find() {
  9. 9 System.out.println("找到了~~");
  10. 10 }
  11. 11
  12. 12 }
  13. 13

c.创建该动态代理类
    

  1. 1 package huguangqin.com.cnblogs.proxy;
  2. 2
  3. 3 import java.lang.reflect.InvocationHandler;
  4. 4 import java.lang.reflect.Method;
  5. 5 import java.lang.reflect.Proxy;
  6. 6
  7. 7 import huguangqin.com.cnblogs.serive.Service;
  8. 8 import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
  9. 9
  10. 10 public class MyProxy implements InvocationHandler {
  11. 11
  12. 12 // 目标接口--我需要知道代理哪个接口
  13. 13 private Service target;
  14. 14
  15. 15 // 代理类的有参构造--利用给我的接口生成 这个接口代理类
  16. 16 public MyProxy(Service target) {
  17. 17 super();
  18. 18 this.target = target;
  19. 19 }
  20. 20
  21. 21 // 获取代理对象--输出该接口的代理代象
  22. 22 public Service getServiceProxy() {
  23. 23 return (Service) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), ServiceImpl.class.getInterfaces(),
  24. 24 this);
  25. 25 }
  26. 26
  27. 27 @Override
  28. 28 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  29. 29 System.out.println("start transaction");
  30. 30 Object invoke = method.invoke(target, args);
  31. 31 System.out.println("end transaction");
  32. 32 return invoke;
  33. 33 }
  34. 34
  35. 35 }
  36. 36

d.创建测试类
    

  1. 1 package huguangqin.com.cnblogs.proxy;
  2. 2
  3. 3 import org.junit.Test;
  4. 4
  5. 5 import huguangqin.com.cnblogs.serive.Service;
  6. 6 import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
  7. 7
  8. 8 public class Demo {
  9. 9
  10. 10 @Test
  11. 11 public void demo() {
  12. 12 // 被代理对象
  13. 13 Service ser = new ServiceImpl();
  14. 14 // 代理工厂
  15. 15 MyProxy mp = new MyProxy(ser);
  16. 16 // 获得代理类
  17. 17 Service proxy = mp.getServiceProxy();
  18. 18 proxy.find();
  19. 19 }
  20. 20 }
  21. 21

2.CGLIB创建动态代理

c.创建动态代理类
    

  1. 1 package huguangqin.com.cnblogs.proxy;
  2. 2
  3. 3 import java.lang.reflect.Method;
  4. 4
  5. 5 import org.springframework.cglib.proxy.Enhancer;
  6. 6 import org.springframework.cglib.proxy.MethodInterceptor;
  7. 7 import org.springframework.cglib.proxy.MethodProxy;
  8. 8
  9. 9 import huguangqin.com.cnblogs.serive.Service;
  10. 10 import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
  11. 11
  12. 12 //cglib
  13. 13 public class MyProxy implements MethodInterceptor {
  14. 14
  15. 15 public Service getMyProxy() {
  16. 16 Enhancer en = new Enhancer();
  17. 17 // 指定父类
  18. 18 en.setSuperclass(ServiceImpl.class);
  19. 19 // 设置需要增强的代码
  20. 20 en.setCallback(this);
  21. 21 // 创建代理对象
  22. 22 return (Service) en.create();
  23. 23
  24. 24 }
  25. 25
  26. 26 @Override
  27. 27 // proxy: 代理对象
  28. 28 // arg1: 目标方法对象
  29. 29 // arg2: 目标方法参数
  30. 30 // methodProxy: 代理方法对象
  31. 31 public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable {
  32. 32 System.out.println("start");
  33. 33 // 调用原业务方法
  34. 34 Object invokeSuper = methodProxy.invokeSuper(proxy, arg2);
  35. 35 System.out.println("end");
  36. 36 return invokeSuper;
  37. 37 }
  38. 38
  39. 39 }
  40. 40

d.测试类
   

  1. 1 package huguangqin.com.cnblogs.test;
  2. 2
  3. 3 import org.junit.Test;
  4. 4
  5. 5 import huguangqin.com.cnblogs.proxy.MyProxy;
  6. 6 import huguangqin.com.cnblogs.serive.Service;
  7. 7
  8. 8 public class Demo {
  9. 9
  10. 10 @Test
  11. 11 public void demo() {
  12. 12 // 代理工厂
  13. 13 MyProxy mp = new MyProxy();
  14. 14 // 获得代理类
  15. 15 Service proxy = mp.getMyProxy();
  16. 16 proxy.find();
  17. 17 }
  18. 18 }
  19. 19

spring笔记3-AOP的更多相关文章

  1. Spring笔记:AOP基础

    Spring笔记:AOP基础 AOP 引入AOP 面向对象的开发过程中,我们对软件开发进行抽象.分割成各个模块或对象.例如,我们对API抽象成三个模块,Controller.Service.Comma ...

  2. Spring笔记(三)AOP前篇之动态代理

    AOP思想是将程序中的业务代码与服务代码进行分离,在运行时进行结合.比较强调程序的层次结构,是一种面向切面的编程.而在AOP实现的底层主要用到了动态代理,而动态代理又分为JDK动态代理和CGLIB动态 ...

  3. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  4. Spring学习笔记(四)—— Spring中的AOP

    一.AOP概述 AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...

  5. Spring学习笔记2—AOP

    1.AOP概念 AOP(Aspect Oriented Programming):面向切面编程,AOP能够将那些与业务无关,却为业务模块所共同调用的应用(例如事务处理.日志管理.权限控制等)封装起来, ...

  6. Spring 3.0 AOP (一)AOP 术语

    关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...

  7. Spring自学教程-AOP学习(五)

    Spring中的AOP 一.概述 (一)基本概念 1.什么是AOP?     面向方面编程.所谓方面即是指日志.权限.异常处理.事务处理等. 2.AOP的3个关键概念    (1)切入点(Pointc ...

  8. Spring笔记02_注解_IOC

    目录 Spring笔记02 1. Spring整合连接池 1.1 Spring整合C3P0 1.2 Spring整合DBCP 1.3 最终版 2. 基于注解的IOC配置 2.1 导包 2.2 配置文件 ...

  9. Spring笔记01_下载_概述_监听器

    目录 Spring笔记01 1.Spring介绍 1.1 Spring概述 1.2 Spring好处 1.3 Spring结构体系 1.4 在项目中的架构 1.5 程序的耦合和解耦 2. Spring ...

  10. 学习 Spring (十二) AOP 基本概念及特点

    Spring入门篇 学习笔记 AOP: Aspect Oriented Programming, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 主要功能是:日志记录.性能统计.安全控 ...

随机推荐

  1. ios配置xmpp即时聊天-服务器端

    一.安装 到MySQL官网上http://dev.mysql.com/downloads/mysql/,下载mysql可安装dmg版本 比如:Mac OS X ver. 10.7 (x86, 64-b ...

  2. 最短路【bzoj1726】: [Usaco2006 Nov]Roadblocks第二短路

    1726: [Usaco2006 Nov]Roadblocks第二短路 Description 贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友.贝茜很喜欢路边的风景,不想那么快地结束她 ...

  3. [USACO09FEB]改造路Revamping Trails 分层最短路 Dijkstra BZOJ 1579

    题意翻译 约翰一共有N)个牧场.由M条布满尘埃的小径连接.小径可 以双向通行.每天早上约翰从牧场1出发到牧场N去给奶牛检查身体. 通过每条小径都需要消耗一定的时间.约翰打算升级其中K条小径,使之成为高 ...

  4. 小程序scroll-view采坑

    scroll-view分为水平滚动和垂直滚动.注意滚动视图垂直滚动时一定要设置高度否则的话scroll-view不会生效.

  5. hdu 6512 Triangle

    Problem Description After Xiaoteng took a math class, he learned a lot of different shapes, but Xiao ...

  6. Kibana问题搜集---下载源码,执行npm install 报错

    npm ERR! code ELIFECYCLEnpm ERR! errno 1npm ERR! chromedriver@2.34.0 install: `node install.js`npm E ...

  7. visual studio检查运算上溢/下溢的开关位置

    [注意] 勾选这个选项会对应用程序的整体性能造成一些影响,但是会更加安全.具体情况根据项目需求来决定.

  8. 2016 Multi-University Training Contest 10 || hdu 5860 Death Sequence(递推+单线约瑟夫问题)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 题目大意:给你n个人排成一列编号,每次杀第一个人第i×k+1个人一直杀到没的杀.然后 ...

  9. iOS自动化测试的那些干货

    前言 如果有测试大佬发现内容不对,欢迎指正,我会及时修改. 大多数的iOS App(没有持续集成)迭代流程是这样的 也就是说,测试是发布之前的最后一道关卡.如果bug不能在测试中发现,那么bug就会抵 ...

  10. python练习六十三:文件处理,读取文件内容,按内容生成文件

    python练习六十三:文件处理 假设要读取code.txt文件中内容,code.txt文件内容如下 01 CN Chinese 02 US United States of America 03 J ...