一.概述

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

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

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

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

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

6.测试
    

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

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

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

2.MyAdvice
   

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

四.动态代理回顾

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

a.编写接口
   

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

b.编写接口的实现类
   

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

c.创建该动态代理类
    

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

d.创建测试类
    

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

2.CGLIB创建动态代理

c.创建动态代理类
    

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

d.测试类
   

  1  package huguangqin.com.cnblogs.test;
2
3 import org.junit.Test;
4
5 import huguangqin.com.cnblogs.proxy.MyProxy;
6 import huguangqin.com.cnblogs.serive.Service;
7
8 public class Demo {
9
10 @Test
11 public void demo() {
12 // 代理工厂
13 MyProxy mp = new MyProxy();
14 // 获得代理类
15 Service proxy = mp.getMyProxy();
16 proxy.find();
17 }
18 }
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. 解读人:林山云,Proteomic Identification of Protein Glutathionylation in Cardiomyocytes(心肌细胞蛋白质谷胱甘肽修饰的蛋白质组鉴定)

    发表时间:(2019年4月) IF:3.950 单位:韦恩州立大学化学系 物种:小鼠心肌细胞 技术:谷胱甘肽修饰蛋白组学 一. 概述: 本研究采用化学选择性蛋白组学方法,鉴定出过氧化物诱导HL-1小鼠 ...

  2. luogu1556 幸福的路

    注意到\(n\le10\),所以枚举经过的拐弯牛的所有排列. 注意到STL是一个好东西,所以我这里偷懒直接使用了next_permutation 枚举所有n的排列,对于每一个排列也就是经过拐弯牛的顺序 ...

  3. java.lang.Exception: No tests found matching(Junit测试异常)

    java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=save], {ExactMatcher:fDispl ...

  4. Qt 学习之路 2(26):反走样

    Qt 学习之路 2(26):反走样 豆子 2012年11月12日 Qt 学习之路 2 9条评论 我们在光栅图形显示器上绘制非水平.非垂直的直线或多边形边界时,或多或少会呈现锯齿状外观.这是因为直线和多 ...

  5. CPU和微架构的概念

    CPU是什么: 中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit). 它的功能主要 ...

  6. ST表(查询区间最值问题)

    ST表与线段树相比,这是静态的,无法改动,但是他的查询速度比线段树要快,这是牺牲空间换时间的算法. O(nlogn)预处理,O(1)查询.空间O(nlogn). ][]; ]; void rmq_in ...

  7. pandas实例美国人口分析

  8. 移动测试之appium+python 导出报告(六)

    下载 HTMLTestRunner.py python3可以参考这个地址 这是针对Python2.7版本 test.py from appium import webdriver import tim ...

  9. Mybatis学习笔记14 - 动态sql之foreach标签

    一.查询给定集合中员工id对应的所有员工信息 示例代码: 接口定义: package com.mybatis.dao; import com.mybatis.bean.Employee; import ...

  10. java多线程(二)

    线程的阻塞状态: 参考java多线程(一)多线程的生命周期图解,多线程的五种状态.     1.1 join(),如果在A线程体里面执行了B线程的join()方法,那么A线程阻塞,直到B线程生命周期结 ...