AOP简介及Schema-base实现前置和后置通知
一、 AOP概述
1.1 什么是AOP?
AOP(Aspect Oriented Programing)面向切面编程。
AOP采取横向抽取机制,取代了传统的继承纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
Spring的AOP采用了纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过动态代理的方式向目标类注入增强代码。
1.2 AOP应用场景说明
- 权限校验
- 日志记录
- 性能监控
- 事务控制.
二、AOP 执行流程
正常程序执行流程都是纵向执行流程
AOP采取横向抽取机制,在demo2执行期间执行 前置通知–>demo2–>后置通知
三、AOP编程
- 又叫面向切面编程,在原有纵向执行流程中添加横切面。
- 不需要修改原有程序代码
- 高扩展性
- 原有功能相当于释放了部分逻辑,让主程序(demo2)职责更加明确
面向切面编程是什么?
- 在程序原有纵向执行流程中,对某一个或某一些方法添加通知,形成横切面的过程。
- 常用概念
- 切点:原有功能 pointcut
- 前置通知:在切点之前执行的功能 before advice
- 后置通知:在切点之后执行的功能 after acvice
- 异常通知:如果切点执行过程中发现异常会触发异常通知 throws advice
- 切面:所有功能总称
- 织入:把切面嵌入原有功能的过程
四、Schema-base实现前置和后置通知
applicationContext.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName">
<!-- 注入通知类 -->
<bean id="myBefore" class="com.zhang.advice.MyBefore"></bean>
<bean id="myAfter" class="com.zhang.advice.MyAfter"></bean>
<aop:config>
<!--
aop:pointcut : 定义切点
expression: 通用配置: execution(* 形成切面的某一个人或者某一些方法,如有参数在方法里添加 .. )
id: 形成的切点 id
-->
<aop:pointcut expression="execution(* com.zhang.pojo.Demo.demo2(..))" id="mypoint"/>
<!--
aop:advisor: 通知
advice-ref: 通知类 bean 的 id
pointcut-ref: 切点id
-->
<aop:advisor advice-ref="myBefore" pointcut-ref="mypoint"/>
<aop:advisor advice-ref="myAfter" pointcut-ref="mypoint"/>
</aop:config>
<bean id="demo" class="com.zhang.pojo.Demo"></bean>
</beans>
前置通知 myBefore 内容如下:
package com.zhang.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyBefore implements MethodBeforeAdvice{
/*
* 1.实现MethodBeforeAdvice接口下的 before方法
* 2.参数列表
* 2.1 Method arg0 : 指明是哪个方法形成了切面
* 2.2 Object[] arg1 : 形成切面方法的参数列表
* 2.3 Object arg2 : 形成切面方法的类对象
*
*/
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("======================");
System.out.println("前置通知");
System.out.println(arg0);
if(arg1.length != 0) {
System.out.println(arg1[0]);
}
System.out.println(arg2);
System.out.println("======================");
}
}
后置通知 myAfter 内容如下:
package com.zhang.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class MyAfter implements AfterReturningAdvice{
/*
* 1.实现AfterReturningAdvice接口下的 afterReturning方法
* 2.参数列表
* 2.1 Object arg0 : 返回的类对象
* 2.2 Method arg1 : 指明是哪个方法形成了切面
* 2.3 Object[] arg2 : 形成切面方法的参数列表
* 2.4 Object arg3 : 形成切面方法的类对象
*
*/
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println("======================");
System.out.println("后置通知");
System.out.println(arg0);
System.out.println(arg1);
if(arg2.length != 0) {
System.out.println(arg2[0]);
}
System.out.println(arg3);
System.out.println("======================");
}
}
Test测试类如下:
package com.zhang.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhang.pojo.Demo;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = applicationContext.getBean("demo",Demo.class);
demo.demo1();
demo.demo2("Mark");
demo.demo3();
}
}
执行Test测试类,其结果如下:
其结果说明在执行 demo2 的方法的时候,形成了切面,并且执行了前后通知。