切入点表达式说明

匹配方法的执行(常用)

execution(表达式)

表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

写法说明:

  • 全匹配方式:
    public void org.cjw.service.impl.CustomerServiceImpl.saveCustomer()
  • 访问修饰符可以省略
    void org.cjw.service.impl.CustomerServiceImpl.saveCustomer()
  • 返回值可以使用号,表示任意返回值
    `
    org.cjw.service.impl.CustomerServiceImpl.saveCustomer()`
  • 包名可以使用号,表示任意包,但是有几级包,需要写几个:
    * *.*.*.*.CustomerServiceImpl.saveCustomer()
  • 使用..来表示当前包,及其子包
    * org..CustomerServiceImpl.saveCustomer()
  • 类名可以使用号,表示任意类
    `
    org..*.saveCustomer()`
  • 方法名可以使用号,表示任意方法
    `
    org...()`
  • 参数列表可以使用,表示参数可以是任意数据类型,但是必须有参数
    `
    org...(*)`
  • 参数列表可以使用..表示有无参数均可,有参数可以是任意类型
    * org..*.*(..)
  • 全通配方式:
    * *..*.*(..)

更多匹配规则请参考这里

基于XML配置AOP

首先介绍通过XML的方式配置AOP。

搭建环境

第一步:创建一个Java项目

需求:编写一个切面类,在执行insert,update方法,分别在方法执行前、执行后、异常出现后、调用编写统一处理的代码。

—创建一个Java项目,加入Spring框架的基础支持包。

Spring AOP使用 - 图1

第二步:编写业务层类和接口

UserService 接口

  1. public interface UserService {
  2. void insert();
  3. void update();
  4. }

业务层UserServiceImpl 实现类

  1. public class UserServiceImpl implements UserService {
  2. @Override
  3. public void insert() {
  4. System.out.println("执行了service层的insert方法");
  5. }
  6. @Override
  7. public void update() {
  8. System.out.println("执行了service层的update方法");
  9. }
  10. }

第三步:编写Spring配置文件

引入aop的命名空间

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <!-- 配置UserService -->
  10. <bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
  11. </beans>

第四步:测试

—测试代码

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class UserServiceTest {
  4. @Resource(name = "userService")
  5. private UserService userService;
  6. @Test
  7. public void testInsert() {
  8. userService.insert();
  9. }
  10. @Test
  11. public void testUpdate() {
  12. userService.update();
  13. }
  14. }

—测试结果

Spring AOP使用 - 图2

配置AOP

第一步:加入AOP的支持包

AOP 思想必须使用AspectJ语法,而AOP思想不是Spring框架设计出来的,而是叫一个AOP联盟组织提出这种思想,所以开发者需要导入AOP联盟提供的 aspectj.weaver.jar(aspectweaver织入包)。

Spring AOP使用 - 图3

第二步:编写一个切面类

  1. public class TransactionMangerHandler {
  2. // 前置增强
  3. public void begin() {
  4. System.out.println("开启事务");
  5. }
  6. // 后置增强
  7. public void commit() {
  8. System.out.println("提交事务");
  9. }
  10. // 异常增强
  11. public void rollback() {
  12. System.out.println("回滚事务");
  13. }
  14. // 最终增强
  15. public void closeSession() {
  16. System.out.println("关闭session");
  17. }
  18. }

第三步:配置AOP配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <!-- 配置UserService -->
  10. <bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
  11. <!-- 配置事务管理器 -->
  12. <bean id="txManger" class="org.cjw.proxyHandler.TransactionMangerHandler" />
  13. <!-- 配置aop -->
  14. <aop:config>
  15. <!-- 配置切面 -->
  16. <aop:aspect ref="txManger">
  17. <!-- 配置切入点:哪些类中的哪些方法需要做增强(where) -->
  18. <aop:pointcut id="pt" expression="execution(* org.cjw.service..*.*(..))" />
  19. <!-- 前置增强 -->
  20. <aop:before method="begin" pointcut-ref="pt" />
  21. <!-- 后置增强 -->
  22. <aop:after-returning method="commit" pointcut-ref="pt" />
  23. <!-- 异常增强 -->
  24. <aop:after-throwing method="rollback" pointcut-ref="pt" />
  25. <!-- 最终增强 -->
  26. <aop:after method="closeSession" pointcut-ref="pt" />
  27. </aop:aspect>
  28. <!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)-->
  29. </aop:config>
  30. </beans>

第四步:测试

测试代码

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class UserServiceTest {
  4. @Resource(name = "userService")
  5. private UserService userService;
  6. @Test
  7. public void testInsert() {
  8. userService.insert();
  9. }
  10. @Test
  11. public void testUpdate() {
  12. userService.update();
  13. }
  14. }

测试结果

Spring AOP使用 - 图4

思考

问题:编写一个切面需要分别编写前置增强、后置增强、异常增强、最终增强,需要使用到4个标签,有没有办法只用一个标签就完成这4种增强呢?

答:使用环绕增强<aop:aorund>

改写切面类

  1. public class TransactionMangerHandler {
  2. // 环绕增强
  3. public void allInOne(ProceedingJoinPoint pjp) {
  4. try {
  5. begin(); // 前置增强
  6. pjp.proceed(); // 执行被调用的方法
  7. commit(); // 后置增强
  8. } catch (Throwable e) {
  9. e.printStackTrace();
  10. rollback(); // 异常增强
  11. } finally {
  12. closeSession(); // 最终增强
  13. }
  14. }
  15. // 前置增强
  16. public void begin() {
  17. System.out.println("开启事务");
  18. }
  19. // 后置增强
  20. public void commit() {
  21. System.out.println("提交事务");
  22. }
  23. // 异常增强
  24. public void rollback() {
  25. System.out.println("回滚事务");
  26. }
  27. // 最终增强
  28. public void closeSession() {
  29. System.out.println("关闭session");
  30. }
  31. }

—aop配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. http://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <!-- 配置UserService -->
  10. <bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
  11. <!-- 配置事务管理器 -->
  12. <bean id="txManger" class="org.cjw.proxyHandler.TransactionMangerHandler" />
  13. <!-- 配置aop -->
  14. <aop:config>
  15. <!-- 配置切面 -->
  16. <aop:aspect ref="txManger">
  17. <!-- 配置切入点:哪些类中的哪些方法需要做增强(where) -->
  18. <aop:pointcut id="pt" expression="execution(* org.cjw.service..*.*(..))" />
  19. <!-- 环绕增强 -->
  20. <aop:around method="allInOne" pointcut-ref="pt" />
  21. </aop:aspect>
  22. <!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)-->
  23. </aop:config>
  24. </beans>

测试代码

同上

测试结果

Spring AOP使用 - 图5

常用标签说明

  • 2.4.1. **<aop:config>**

作用:用于声明aop配置

  • 2.4.2. **<aop:aspect>**

作用: 用于配置切面。

属性:

  1. - id:给切面一个唯一标识。
  2. - ref:引用配置好的切面类beanid
  • 2.4.3.<aop:pointcut>

作用:用于配置切入点表达式

属性:

  1. - id:用于给切入点表达式一个唯一标识。
  2. - expression:用于定义切入点表达式。
  • 2.4.4. <aop:before>

作用:用于配置前置通知

属性:

  1. - method:指定通知中方法的名称。
  2. - pointct:定义切入点表达式
  3. - pointcut-ref:指定切入点表达式的引用
  • 2.4.5. <aop:after-returning>

作用:用于配置后置通知,如果出了异常就一定不会调用切面的方法

属性:

  1. - method:指定通知中方法的名称。
  2. - pointct:定义切入点表达式
  3. - pointcut-ref:指定切入点表达式的引用
  • 2.4.6. <aop:after-throwing>

作用: 用于配置异常通知,只有出了异常才会调用切面对应的方法

属性:

  1. - method:指定通知中方法的名称。
  2. - pointct:定义切入点表达式
  3. - pointcut-ref:指定切入点表达式的引用
  • 2.4.7. <aop:after>

作用:用于配置最终通知,不管出不出异常,都调用切面的方法

属性:

  1. - method:指定通知中方法的名称。
  2. - pointct:定义切入点表达式
  3. - pointcut-ref:指定切入点表达式的引用
  • 2.4.8. <aop:around>

作用:用于配置环绕通知

属性:

  1. - method:指定通知中方法的名称。
  2. - pointct:定义切入点表达式
  3. - pointcut-ref:指定切入点表达式的引用

基于注解配置AOP

接下来介绍基于注解的方式配置AOP。

搭建环境

第一步:创建一个Java项目

同上。

第二步:创建UserService接口及其实现类

  1. public interface UserService {
  2. void insert();
  3. void update();
  4. }
  5. @Service
  6. public class UserServiceImpl implements UserService {
  7. @Override
  8. public void insert() {
  9. System.out.println("执行了service层的insert方法");
  10. }
  11. }

第三步:编写Spring配置类

  1. @Configuration
  2. @ComponentScan(basePackages = "org.cjw")
  3. public class SpringConfig {
  4. }

第四步:测试

测试代码

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = SpringConfig.class)
  3. public class UserServiceTest {
  4. @Autowired
  5. @Qualifier("userService")
  6. private UserService userService;
  7. @Test
  8. public void testInsert() {
  9. userService.insert();
  10. }
  11. }

测试结果

Spring AOP使用 - 图6

配置AOP

第一步:加入AOP的支持包

—注意:必须要导入加入支持AOP的包。

Spring的AOP包基于AspectJ框架,所以必须加入AspectJ—>aspectjweaver.jar。

第二步:编写一个切面类

  1. @Component
  2. @Aspect
  3. public class TransactionMangerHandler {
  4. // 环绕增强
  5. @Around("pointcut()")
  6. public void allInOne(ProceedingJoinPoint pjp) {
  7. try {
  8. begin(); // 前置增强
  9. pjp.proceed(); // 执行被调用的方法
  10. commit(); // 后置增强
  11. } catch (Throwable e) {
  12. e.printStackTrace();
  13. rollback(); // 异常增强
  14. } finally {
  15. closeSession(); // 最终增强
  16. }
  17. }
  18. @Pointcut("execution(* org.cjw..*.*(..))") // 等价于<aop:pointcut id="等价于方法名" expression="execution(* org.cjw..*.*(..))">
  19. public void pointcut() {}
  20. // 前置增强
  21. @Before("pointcut()") // 等价于<aop:before method="begin" pointcut-ref="pt" />
  22. public void begin() {
  23. System.out.println("开启事务");
  24. }
  25. // 后置增强
  26. @AfterReturning("pointcut()") // 等价于<aop:after-returning method="commit" pointcut-ref="pt" />
  27. public void commit() {
  28. System.out.println("提交事务");
  29. }
  30. // 异常增强
  31. @AfterThrowing("pointcut()") // 等价于<aop:after-throwing method="rollback" pointcut-ref="pt" />
  32. public void rollback() {
  33. System.out.println("回滚事务");
  34. }
  35. // 最终增强
  36. @After("pointcut()") // 等价于<aop:after method="closeSession" pointcut-ref="pt" />
  37. public void closeSession() {
  38. System.out.println("关闭session");
  39. }
  40. }

第三步:配置AOP配置

  1. @Configuration
  2. @ComponentScan(basePackages = "org.cjw")
  3. @EnableAspectJAutoProxy // 开启注解配置AOP
  4. public class SpringConfig {
  5. }

第四步:测试

—测试代码

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = SpringConfig.class)
  3. public class UserServiceTest {
  4. @Autowired
  5. @Qualifier("userService")
  6. private UserService userService;
  7. @Test
  8. public void testInsert() {
  9. userService.insert();
  10. }
  11. }

测试结果

Spring AOP使用 - 图7

常用注解

  • @Aspect

作用:把当前类声明为切面类。

  • @Before

作用:把当前方法看成是前置通知。

属性:

value:用于指定切入点表达式,还可以指定切入点表达式的引用。

  • @AfterReturning

作用:把当前方法看成是最终通知。报异常,就不执行。

属性:

value:用于指定切入点表达式,还可以指定切入点表达式的引用。

  • @AfterThrowing

作用:把当前方法看成是异常通知。只有报异常才执行

属性:

value:用于指定切入点表达式,还可以指定切入点表达式的引用。

例子:

Spring AOP使用 - 图8

  • @After

作用:把当前方法看成是后置通知。不管报不报异常都执行

属性:

value:用于指定切入点表达式,还可以指定切入点表达式的引用。

  • @Around

作用:把当前方法看成是环绕通知。

属性:

value:用于指定切入点表达式,还可以指定切入点表达式的引用。

  • @Pointcut

作用:指定切入点表达式

属性:

value:指定表达式的内容

综合例子

  1. @Aspect
  2. @Component
  3. public class NotVeryUsefulAspect {
  4. @AfterReturning(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
  5. private void logReceiver(){
  6. System.out.println("切入点logReceiver...");
  7. }
  8. @Pointcut(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..)) && args(param)")
  9. private void pointcut(String param){
  10. System.out.println("切入点pointcut()"+param);
  11. }
  12. //方法体将不执行
  13. @Pointcut("within(com.cn.spring.aspectj.*)")
  14. public String inWebLayer() {
  15. System.out.println("切入点inWebLayer()");
  16. return "返回值加载";
  17. }
  18. @Before(value="inWebLayer()")
  19. private void beforeinWebLayer(){
  20. System.out.println("beforeinWebLayer~~");
  21. }
  22. @Before(value="pointcut(param)")
  23. private void beforePointcut(String param){
  24. System.out.println("beforePointcut:"+param);
  25. }
  26. @AfterReturning(pointcut="inWebLayer()",returning="retVal")
  27. public void doAccessCheck(Object retVal) {
  28. System.out.println("doAccessCheck:"+retVal);
  29. }
  30. @Around(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
  31. private Object aroundLayer(ProceedingJoinPoint pjp) throws Throwable{
  32. // start stopwatch
  33. Object retVal = pjp.proceed();
  34. // stop stopwatch
  35. System.out.println("aroundLayer~~");
  36. return retVal;
  37. }
  38. }

Spring AOP使用小结

Spring AOP xml配置

(1) 在xml配置文件中引入新的aop命名空间。

(2) Springaop XML配置标签

<aop:config> 开启aop配置,aop所有配置都在此标签内部配置

  1. <aop:ponitcut exepression=”切入点语法” id=””>配置切入点

  2. <aop:apect ref=”引入要增强的bean(事务管理器)” > 配置切面

    a.<aop:before>前置通知
    b.<aop:aftereturning>后置通知
    c.<aop:afterthrowing>异常通知
    d.<aop:after>最终通知
    e.<aop:around>环绕通知

Spring AOP 注解配置

(1) 在配置文件/配置类开启注解配置。

  1. xml`<aop:aspectj-autoproxy/>`<br /> annotation:在java配置类中贴上`@EnableAspectJAutoProxt`注解,作用等同于在xml配置文件中编写`<aop:aspectj-autoproxy>`

(2) @Aspect 在类贴上这个注解,把对应的类当前切面配置类。

(3) @Pointcut 切入点注解

(4)@Before前置通知注解

(5)@After 后置通知注解

(6)@Aftertrhowing异常通知注解

(7)@Afterreturing 最终通知注解

(8) @Around环绕通知注解