AOP(Aspect Oriented Programming)
概念
意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
官方SpringAOP名词解释
Aspect
:是通过使用常规类(schema-based approach)或使用@Aspect
注解(@AspectJ style)注解 的常规类来实现的。
Join point
:在程序执行过程中的一点,例如方法的执行或异常的处理。在 Spring AOP 中,连接点始终代表方法的执行。
Advice
:方面在特定的连接点处采取的操作。不同类型的建议包括“周围”,“之前”和“之后”建议。 (建议类型将在后面讨论.)包括 Spring 在内的许多 AOP 框架都将建议建模为拦截器,并在连接点周围维护一系列拦截器
Pointcut
:与连接点匹配的谓词。建议与切入点表达式关联,并在与该切入点匹配的任何连接点处运行(例如,执行具有特定名称的方法)。切入点表达式匹配的连接点的概念是 AOP 的核心,并且 Spring 默认使用 AspectJ 切入点表达语言。
Introduction
:代表类型声明其他方法或字段。 Spring AOP 允许您向任何建议的对象引入新的接口(和相应的实现)。例如,您可以使用简介使 Bean 实现IsModified
接口,以简化缓存。 (在 AspectJ 社区中,介绍被称为类型间声明.)
Target object
:一个或多个方面建议的对象。也称为“建议对象”。由于 Spring AOP 是使用运行时代理实现的,因此该对象始终是代理对象。
AOP proxy
:由 AOP 框架创建的一个对象,用于实现方面协定(建议方法执行等)。在 Spring Framework 中,AOP 代理是 JDK 动态代理或 CGLIB 代理。
Weaving
:将方面与其他应用程序类型或对象链接以创建建议的对象。这可以在编译时(例如,使用 AspectJ 编译器),加载时或在运行时完成。像其他纯 Java AOP 框架一样,Spring AOP 在运行时执行编织。
通俗来讲的名词含义
AOP会对某个请求的方法也可以是注解标注的方法进行拦截,通过拦截可以让我们在方法的前后加上一些其他功能的代码,来达到扩展的功能。
Aspect
:切面用来描述一个切面类,可以理解为拦截的整个方法,最后还是会通过Spring 来管理这个切面类
Pointcut
:切入点也就是我要作用在什么方法上,或者某个注解上,通过两种方式注入
- execution表达式
- annotation注解
Advice
:增强,AOP是用来增加功能,Advice就是表示要在什么时候增加方法。处理方法的时机和自己定义的内容
- before(前置处理)
- After(后置处理)
- Around(环绕处理)
- AfterReturing(后置返回通知)
- AfterThrowing(异常处理)
Join point
:方法、字段、构造器等等哪些可以被增强,这些就称为连接点。Target object
:目标对象也就是代理对象weave
: 织入就是把AOP功能织入到原来的系统中
通过注解配置AOP
通过一个给方法加上一个自定义注解就输入织入成功
1、声明一个自定义注解@MyDiyAnnotation
,用于标注到实现Aop的方法上
package com.ylc.service.annotation; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyDiyAnnotation { }
2、创建一个AOP类,通过@Aspect用来描述一个切面类,然后加上@Component注解,把该类交给 Spring 来管理
@Component //将该类交给 Spring 来管理 @Aspect //用来描述一个切面类 public class TestAop { @Pointcut("@annotation(com.ylc.service.annotation.MyDiyAnnotation)") private void logAdvicePointcut() {} // Before表示logAdvice将在目标方法执行前执行 @Before("logAdvicePointcut()") public void before(){ System.out.println("-----前置通知before-----"); } @AfterReturning("logAdvicePointcut()") public void afterrunning(){ System.out.println("-----后置通知AfterReturning-----"); } @After("logAdvicePointcut()") public void after(){ System.out.println("-----后置通知after-----"); } @Around("logAdvicePointcut()") public void xxx(ProceedingJoinPoint pj) { try { System.out.println("环绕通知开始 ..."); pj.proceed(); System.out.println("环绕通知结束 ..."); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
3、创建一个登录请求,里面标注自定义注解@MyDiyAnnotation
@RestController public class MyLoginService { @GetMapping("/login") @MyDiyAnnotation public String Login() { System.out.println("【登录成功】"); return "success"; } }
try{ try{ doBefore();//对应@Before注解的方法切面逻辑 method.invoke(); }finally{ doAfter();//对应@After注解的方法切面逻辑 } doAfterReturning();//对应@AfterReturning注解的方法切面逻辑 }catch(Exception e){ doAfterThrowing();//对应@AfterThrowing注解的方法切面逻辑 }
网上一张图片解释的很清晰,注解配置通知的执行顺序,但使用xml的顺序会不一样
通过XML配置AOP
1、声明一个自定义注解@MyDiyAnnotation
,用于标注到实现Aop的方法上
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) public @interface MyDiyAnnotation { }
2、创建一个AOP类
@Component //将该类交给 Spring 来管理 @Aspect //用来描述一个切面类 public class TestAop { public void before(){ System.out.println("-----前置通知before-----"); } public void afterrunning(){ System.out.println("-----后置通知AfterReturning-----"); } public void after(){ System.out.println("-----后置通知after-----"); } public void around(ProceedingJoinPoint pj) { try { System.out.println("环绕通知开始 ..."); pj.proceed(); System.out.println("环绕通知结束 ..."); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
3、在方法中标注自定义注解@MyDiyAnnotation
public class User { public String name; public Integer age; public User() { } @MyDiyAnnotation public void Play() { System.out.println("打羽毛球"); } }
4、springAop.xml
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="user1" class="com.ylc.service.Entity.User"></bean> <bean id="aspetbean" class="com.ylc.service.aop.TestAop"></bean> <aop:config> <!--ref表示在哪个类中增强--> <aop:aspect id="aspect1" ref="aspetbean"> <!--切入点表达式--> <aop:pointcut id="pointcut" expression="@annotation(com.ylc.service.annotation.MyDiyAnnotation)" /> <!--引用哪些增强类 对哪个切点增强--> <aop:after-returning method="afterReturning" pointcut-ref="pointcut" /> <aop:after method="after" pointcut-ref="pointcut" /> <aop:around method="around" pointcut-ref="pointcut" /> <aop:before method="before" pointcut-ref="pointcut" /> </aop:aspect> </aop:config> </beans>
5、方法测试
@Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext("springAop.xml"); User user2 = (User)ctx.getBean("user1"); user2.Play(); }
测试结果1
测试结果二
总结
xml中是可以自定义顺序的