Spring通过动态代理模式的实现后,我们可以定义AOP其实就是用于通过规则设置来拦截方法,加入可以统一处理的代码。
规则:
可以指定哪些方法要做增强,哪些方法不做增强,由Spring的AOP 统一配置即可,底层如果被代理的类有接口使用JDK动态代理,没有接口自动CGLIB第三方代理,开发者只要配置AOP即可,不需要再编写底层动态代理的相关代码。
AOP相关术语
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
—就是根据规则,可以指定拦截的方法,我们将每一个被拦截的方法称为连接点。
Pointcut(切入点):
--所谓的切入点,就是拦截方法设置的规则
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):
--就是可以设置在方法之前拦截或者方法执行之后拦截或者方法出异常后拦截,或者方法之前和之后都拦截。我们将这些拦截场景称为通知
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Aspect(切面):
--所谓的切面就是我们的拦截处理类。
是切入点和通知的结合。
Weaving(织入):
把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)
常用标签
<aop:config>
作用:
用于声明开始aop的配置
<aop:aspect>
作用:
用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类bean的id。
<aop:pointcut>
作用:
用于配置切入点表达式
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识。
<aop:before>
作用:
用于配置前置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after-returning>
作用:
用于配置后置通知,如果出了异常就一定不会调用切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after-throwing>
作用:
用于配置异常通知,只有出了异常才会调用切面对应的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:after>
作用:
用于配置最终通知,不管出不出异常,调用的切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
<aop:around>
作用:
用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
搭建环境
UserService 接口
package com.ywq.spring.service;
import com.ywq.spring.pojo.User;
public interface UserService {
void insert(User user);
void update(User user);
}
业务层UserServiceImpl 实现类
package com.ywq.spring.service.impl;
import com.ywq.spring.pojo.User;
import com.ywq.spring.service.UserService;
public class UserServiceImpl implements UserService{
public void insert(User user) {
System.out.println("---调用DAO层保存方法---");
}
public void update(User user) {
System.out.println("---调用DAO层修改方法---");
}
}
切面类
package com.ywq.spring;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class TransactionManagerHandler {
/**
* 环绕增强的方法
*
* @param pjp ProceedingJoinPoint 连接点 ProceedingJoinPoint 连接点
*
*/
public void allInOne(ProceedingJoinPoint pjp) {
try {
begin(pjp);
// 执行方法
pjp.proceed(); //此方法在环绕方法中可以调用正在的业务方法
System.out.println("提交事务");
} catch (Throwable e) {
System.out.println("回滚事务 :" + e.getMessage());
} finally {
System.out.println("关闭session");
}
}
// JoinPoint : 连接点, 获取被代理对象的相关信息
public void begin(JoinPoint jp) {
// 获取被代理对象的类型
Class<?> clz = jp.getTarget().getClass();
System.out.println(clz);
// 获取被代理对象执行方法对应的参数
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
System.out.println("开启事务");
}
public void begin() {
System.out.println("开启事务");
}
public void commit() {
System.out.println("提交事务");
}
/*
* public void rollback() { System.out.println("回滚事务"); }
*/
public void rollback(Throwable e) {
System.out.println("回滚事务 : " + e.getMessage());
}
public void close() {
System.out.println("关闭session");
}
}
XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 配置UserService层 -->
<bean id="userService" class="com.ywq.spring.service.impl.UserServiceImpl"/>
<!-- 配置事物管理器 -->
<bean id="txMananger" class="com.ywq.spring.TransactionManagerHandler"/>
<!-- AOP 相关配置: W (where)W(when)W(what) 原则 -->
<!-- 配置切入点: where -->
<aop:config>
<!-- 做什么(what:增强的功能) -->
<aop:aspect ref="txMananger">
<!-- 切入点(Pointcut):在哪些类,哪些方法上切入(where); -->
<aop:pointcut expression="execution( * com.ywq.spring.service..*.*(..))" id="pt"/>
<!-- 增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)
前置增强 : method : 需要增强的方法 -->
<aop:before method="begin" pointcut-ref="pt"/>
<aop:after-returning method="commit" pointcut-ref="pt"/><!-- 后置增强 -->
<!-- 异常增强 : 抛出的异是常异常顶级类Throwable
throwing : 是异常增城方法,参数的名称: 必须和参数一致 -->
<aop:after-throwing throwing="e" method="rollback" pointcut-ref="pt"/><!-- 异常增强 -->
<aop:after method="close" pointcut-ref="pt"/><!-- 最终增强 -->
<!-- 环绕增强: 将多个增加集中到一起了 -->
<!-- <aop:around method="allInOne" pointcut-ref="pt"/> -->
</aop:aspect>
<!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。 -->
</aop:config>
</beans>
测试代码
package com.ywq.spring.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ywq.spring.pojo.User;
import com.ywq.spring.service.impl.UserServiceImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {
@Resource
private UserServiceImpl service;
@Test
public void testSave() {
User user = new User(null, "张三", "[email protected]");
service.insert(user);
}
@Test
public void testUpdate() {
User user = new User(1, "李四", "[email protected]");
service.update(user);
}
}