AOP:Aspect Oriented Programming,面向切面编程,
把业务代码中公共的代码抽离出来。然后再通过动态代理的方式动态的切入到页面代码中。
就跟抽方法一个道理,抽公共的部分,但是并不在类中再调用,而是在事务管理器里面织入(规定通知的执行顺序)
使用:事务管理,日志管理,性能监测,权限校验;
===============================================================
AOP术语
连接点(Joinpoint):程序执行的某一个特定位置,如类初始前后,方法的运行前后。而Spring只支持方法的连接点。
切点(Pointcut):切点可以定位到相应的连接点,一个切点可以定位多个连接点。
增强(Advice):又被称为通知,完成逻辑的增强。
目标对象(Target):增强逻辑织入的目标类。
引介(Introduction):特殊的增强,为类添加一些属性和方法。
织入(Weaving): 将增强添加到目标类的具体连接点上的过程。Spring使用动态代理织入。
代理(Proxy):一个类(原类)被织入增强(逻辑)后,就产生一个结果类,称为代理类。
切面(Aspect):由切点和增强组成
===================================================================
自己完成动态代理是非常麻烦的,但Spring已经把动态代理部分完成,我们只需要做一些简单的配置(通过xml或者使用注解)就可以完成相应的功能。
配置三个要素:何时,何地,做什么事
何时:在目标对象的连接点的之前/之后/有异常…
何地:在哪些包中的哪些类的哪些方法上面执行(确定目标对象的连接点)
做什么事: 在何时何地执行管理器中的哪个方法
==================================================================
导包:pom.xml中
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
一、Xml版实现AOP
1、事务管理器
/**
* 切面类。事务管理器
*/
public class TxManager {
public void start() {
System.out.println("开启事务");
}
public void commit() {
System.out.println("提交事务");
}
public void rollback(Throwable throwable) {
System.out.println("回滚事务,原因是:" + throwable.getMessage());
}
public void close() {
System.out.println("关闭事务");
}
/**
* 如果用>=2个通知,那么建议使用环绕通知,且不需要用另外几个通知,
* 原因一:因为那几个通知的执行是没有顺序的,比如after和after-returning
* 二:因为会重复,它们同时存在的情况下,其他通知不会被取消
*/
public void around(ProceedingJoinPoint joinPoint) {
try {
start();
//就是调用目标类的方法
joinPoint.proceed();
commit();
} catch (Throwable e) {
rollback(e);
} finally {
close();
}
}
}
2、配置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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="txManager" class="cn.itsource._03_aop.TxManager"/>
<bean id="userService" class="cn.itsource._03_aop.service.impl.UserServiceImpl"/>
<bean id="deptService" class="cn.itsource._03_aop.service.impl.DeptServiceImpl"/>
<!--aop:config:配置一个AOP-->
<aop:config>
<!--aop:pointcut配置一个切点
expression:正则表达式,表示要在哪些类的哪些方法上加通知,就是何地
第一个*:表示所有的返回值,
第二个*:表示所有以I开头,以Service结束的类
..:表示任意的参数-->
<aop:pointcut id="txPointCut"
expression="execution(* cn.itsource._03_aop.service.I*Service.save(..))"/>
<!--aop:aspect:切面配置,
ref:应用哪个bean作为切面类,就是事务管理器-->
<aop:aspect ref="txManager">
<!--before 前置通知,method表示调用切面类的方法-->
<aop:before method="start" pointcut-ref="txPointCut"/>
<!--after-returning后置通知-->
<aop:after-returning method="commit" pointcut-ref="txPointCut"/>
<!--after-throwing异常通知-->
<aop:after-throwing method="rollback" pointcut-ref="txPointCut" throwing="throwable"/>
<!--after 最终通知-->
<aop:after method="close" pointcut-ref="txPointCut"/>
<!--around 环绕通知-->
<!--<aop:around method="around" pointcut-ref="txPointCut"/>-->
</aop:aspect>
</aop:config>
</beans>
================================================================
二、注解版实现AOP(推荐,因为不用繁琐的配置)
1、事务管理器
@Component
@Aspect //AOP的类注解,表示这个类是一个特殊的组件
public class TxManager {
//设置切点
@Pointcut("execution(* cn.itsource.aopanno.I*Service.*(..))")
//是个空方法,给通知用
public void pointcut(){}
//前置通知
@Before("pointcut()")
public void begin(){
System.out.println("开启事务....");
}
//后置通知
@AfterReturning("pointcut()")
public void commit(){
System.out.println("提交事务...");
}
//异常通知
@AfterThrowing(pointcut="pointcut()",throwing="e")
public void rollback(Throwable e){
System.out.println("回滚事务....");
System.out.println(e.getMessage());
}
//最终通知
@After("pointcut()")
public void close(){
System.out.println("关闭资源....");
}
//@Around("pointcut()")//同样的,建议使用
public Object around(ProceedingJoinPoint joinPoint){
Object object = null;
try {
begin();
object = joinPoint.proceed(); //执行相应的代码
commit();
} catch (Throwable e) {
rollback(e);
}finally{
close();
}
return object;
}
}
2、配置文件
<!-- 组件搜索 -->
<context:component-scan base-package="cn.itsource" />
<!-- 支持aop注解 -->
<aop:aspectj-autoproxy />
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringTest {
@Autowired
//这里注入的一定是接口,在Spring实现动态代理中有解释
private IUserService userService;
@Autowired
private IDeptService deptService;
@Test
public void test() {
userService.save();
}
@Test
public void test2() {
deptService.save();
}
}