[Spring+SpringMVC+Mybatis]框架学习笔记(六):Spring_AspectJ实现AOP
2019-07-08 15:39
1631 查看
第6章 Spring_AspectJ实现AOP
6.1 什么是AspectJ
对于AOP的这种编程思想,有很多框架或者组件进行了实现,spring实现AOP就是其中的一种。
AspectJ也实现了AOP,而且实现方式更为简单,使用起来更为方便,所以spring将AspectJ对于AOP的实现引入了自己的框架。
AspectJ是一个面向切面的框架,它定义了AOP的一些语法,有一个专门的字节码生成器来生成遵守java规范的class文件。
AspectJ的通知类型:
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知:无论程序是否正常执行,最终通知的代码会得到执行,类似于try...catch...finally
6.2 切入点表达式
切入点表达式作用:标识切面织入到哪些类的哪些方法当中。
- 语法格式如下:
public boolean com.steven.spring.service.impl.StudentService.addStudent(Student student) execution( modifiers-pattern? //访问权限匹配 如public、protected 问号代表可以省略 ret-type-pattern //返回值类型匹配 declaring-type-pattern? //全限定性类名 name-pattern(param-pattern) //方法名(参数名) throws-pattern? //抛出异常类型 )
注意:中间以空格隔开,有问号的属性可以省略
- 特殊符号
a: * 代表0到多个任意字符 b: .. 放在方法参数中 ,代表任意个参数 ,放在包名后面表示当前包及其所有子包路径 c: + 放在类名后,表示当前类及其子类,放在接口后,表示当前接口及其实现类
- 例如:
a:execution(public * *(..)) 表示任意的public方法 b:execution(* set*(..)) 表示任意包含以set字符开头的方法 c:execution(* com.steven.spring.service.impl.*.*(..)) 表示com.steven.spring.service.impl的任意类的任意方法 d:execution(* com.steven.spring.service..*.*(..)) 表示com.steven.spring.service包下面的所有方法以及所有子包下面的所有方法 e:execution(* com.steven.spring.service.IStudentService+.*(..)) f:execution(* add(String,int)) 带包任意返回类型的add方法 有两个参数,类型分别为String,int g:execution(* add(String,*))
6.3 AspectJ+Spring的环境搭建
引入jar包
经测试,可以不用另外加上spring-aspects-4.2.1.RELEASE.jar。但aspectjweaver一定不能少。
引入aop的约束
6.4 Aspect的配置方式
6.4.1 基于xml的方式
实现步骤:
- 编写切面类
- 在切面类里面定义各种通知的实现方法
- 在配置文件里面对aop进行配置 ,详见applicationContext.xml
实例:
1)实体类
package com.steven.spring.sysmanage.entity; /** * 学生实体类 * @author Administrator * */ public class Student implements java.io.Serializable{ private static final long serialVersionUID = -3875695558042397898L; private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
2)服务类接口
package com.steven.spring.sysmanage.service; import java.util.List; import com.steven.spring.sysmanage.entity.Student; /** * 用于对外提供学生服务类的增删改查接口 * @author Administrator * */ public interface IStudentService { public boolean addStudent(Student student); public boolean delStudent(Integer studentId); public boolean updateStudent(Student student); public List<Student> getStudentList(); }
3)服务类
package com.steven.spring.sysmanage.service.impl; import java.util.ArrayList; import java.util.List; import com.steven.spring.sysmanage.entity.Student; import com.steven.spring.sysmanage.service.IStudentService; /** * 用于对外提供学生服务类的增删改查实现 * @author Administrator * */ public class StudentService implements IStudentService{ @Override public boolean addStudent(Student student) { //System.out.println("进行权限验证"); System.out.println("执行增加功能"); //System.out.println("进行日志记录"); return true; } @Override public boolean delStudent(Integer studentId) { //System.out.println("进行权限验证"); int i= 1/0; System.out.println("执行删除功能"); //System.out.println("进行日志记录"); return true; } @Override public boolean updateStudent(Student student) { //System.out.println("进行权限验证"); System.out.println("执行修改功能"); //System.out.println("进行日志记录"); return true; } @Override public List<Student> getStudentList() { //System.out.println("进行权限验证"); System.out.println("执行查询功能"); //System.out.println("进行日志记录"); return new ArrayList<Student>(); } }
4)定义通知
package com.steven.spring.sysmanage.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * 基于xml配置方式实现aspectJ 定义通知 * @author chenyang * */ public class MyAspect { //定义前置通知 public void beforeAdvice(){ System.out.println("这是一个前置通知,应该在目标方法之前打印出来"); } //定义后置通知 public void afterAdvice(){ System.out.println("这是一个后置通知,应该在目标方法之后打印出来"); } //定义后置通知,包含返回值 public void afterAdvice(Object result){ System.out.println("这是一个后置通知,应该在目标方法之后打印出来;目标方法的返回值为:" + result.toString()); } //定义环绕通知 public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("这是一个环绕通知,应该在目标方法之前打印出来"); Object result = pjp.proceed(); System.out.println("这是一个环绕通知,应该在目标方法之后打印出来"); } //定义异常通知 public void afterThrowingAdvice(){ System.out.println("这是一个异常通知,应该在目标方法出现异常之后打印出来"); } //定义异常通知,包含返回值 public void afterThrowingAdvice(Exception ex){ System.out.println("这是一个异常通知,应该在目标方法出现异常之后打印出来,异常为:" + ex); } //定义最终通知 public void lastAdvice(){ System.out.println("这是一个最终通知,无论如何都会执行"); } }
5)配置文件
<?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:context="http://www.springframework.org/schema/context" 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/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"> <!-- 注册目标类 --> <bean id="studentService" class="com.steven.spring.sysmanage.service.impl.StudentService"></bean> <!-- 注册切面(通知) --> <bean id="myAspect" class="com.steven.spring.sysmanage.aspect.MyAspect"></bean> <!-- AspectJ的aop配置 --> <aop:config> <aop:pointcut expression="execution(* add*(..))" id="beforePointCut"/> <aop:pointcut expression="execution(* update*(..))" id="afterPointCut"/> <aop:pointcut expression="execution(* get*(..))" id="aroundPointCut"/> <aop:pointcut expression="execution(* del*(..))" id="afterThrowingPointCut"/> <aop:pointcut expression="execution(* del*(..))" id="lastPointCut"/> <aop:aspect ref="myAspect"> <aop:before method="beforeAdvice" pointcut-ref="beforePointCut"/> <aop:after-returning method="afterAdvice" pointcut-ref="afterPointCut" /> <!-- 方法参数必须是全路径类名 返回值参数名必须与方法中参数名一致 --> <aop:after-returning method="afterAdvice(java.lang.Object)" pointcut-ref="afterPointCut" returning="result" /> <aop:around method="aroundAdvice" pointcut-ref="aroundPointCut"/> <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="afterThrowingPointCut"/> <aop:after-throwing method="afterThrowingAdvice(java.lang.Exception)" pointcut-ref="afterThrowingPointCut" throwing="ex" /> <aop:after method="lastAdvice" pointcut-ref="lastPointCut"/> </aop:aspect> </aop:config> </beans>
6)测试
package com.steven.spring.sysmanage.test; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmanage.entity.Student; import com.steven.spring.sysmanage.service.IStudentService; public class AspectXmlTest { private ApplicationContext ac = null; private IStudentService studentService = null; @Before public void init(){ ac = new ClassPathXmlApplicationContext("applicationContext.xml"); studentService = (IStudentService) ac.getBean("studentService"); } //测试前置通知 @Test public void testBeforeAdvice(){ studentService.addStudent(new Student()); } //测试后置通知 @Test public void testAfterAdvice(){ studentService.updateStudent(new Student()); } //测试环绕通知 @Test public void testAroundAdvice(){ studentService.getStudentList(); } //测试异常通知 @Test public void testAfterThrowingAdvice(){ studentService.delStudent(1); } //测试最终通知 @Test public void testLastAdvice(){ studentService.delStudent(1); } }
6.4.2 基于注解的方式
注解方式有一定的侵入性(在代码中加入原本不属于代码的部分)。
实现步骤:
- 编写切面类,加上@Aspect注解
- 实现各种通知,在实现通知的方法上加上通知的注解以及切入点表达式的注解
- 在配置文件注册切面,且加上aspectJ的自动代理
实例:
在6.4.1实例的基础上更改通知类和配置文件,最后在测试类中更改配置文件名称即可。
1)通知类
package com.steven.spring.sysmanage.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** * 基于xml配置方式来实现AspectJ 定义通知 * @author Administrator * */ @Aspect public class MyAspectAnnotation { //定义前置通知 @Before(value="execution(* add*(..))") public void beforeAdvice(){ System.out.println("这是一个前置通知,应该在目标方法之前打印出来"); } //定义后置通知 @AfterReturning(value="execution(* update*(..))") public void afterAdvice(){ System.out.println("这是一个后置通知,应该在目标方法之后打印出来"); } //定义后置通知包含返回值 @AfterReturning(value="execution(* update*(..))",returning="result") public void afterAdvice(Object result){ System.out.println("这是一个后置通知,应该在目标方法之后打印出来"); System.out.println("后置通知得到目标方法的返回值="+result.toString()); } //定义环绕通知 @Around(value="execution(* get*(..))") public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("这是一个环绕通知,应该在目标方法之前打印出来"); Object result = pjp.proceed(); System.out.println("这是一个环绕通知,应该在目标方法之后打印出来"); } //定义异常通知 @AfterThrowing(value="execution(* del*(..))") public void afterThrowingAdvice(){ System.out.println("这是一个异常通知,应该在目标方法出现异常时候打印出来"); } //定义异常通知 @AfterThrowing(value="execution(* del*(..))",throwing="ex") public void afterThrowingAdvice(Exception ex){ System.out.println("这是一个异常通知,应该在目标方法出现异常时候打印出来 ex="+ex); } //定义最终通知 finally @After(value="execution(* del*(..))") public void lastAdvice(){ System.out.println("这是一个最终通知,无论如何会执行 "); } }
2)配置文件
<?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:context="http://www.springframework.org/schema/context" 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/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"> <!--注册studentService --> <bean id = "studentService" class = "com.steven.spring.sysmanage.service.impl.StudentService"> </bean> <!--注册切面 --> <bean id= "myAspect" class = "stevenm.tz.spring.sysmanage.aspect.MyAspectAnnotation"></bean> <aop:aspectj-autoproxy/> </beans>
相关文章推荐
- [Spring+SpringMVC+Mybatis]框架学习笔记(一):SpringIOC概述
- 学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发
- 【Spring学习笔记-MVC-5】利用spring MVC框架,实现ajax异步请求以及json数据的返回
- 学习笔记--代理与AOP及实现类似SPRING的可配置的AOP框架
- Spring AOP框架学习笔记(2):AOP拦截器调用的实现
- Maven学习笔记(五)-Maven整合SSM(spring+springMVC+Mybatis)框架
- Spring+SpringMVC+Mybatis框架整合例子(SSM) 学习笔记
- 学习笔记之springAOP的aspectJ实现注意点总结
- SpringMVC + Spring + MyBatis 学习笔记:SpringMVC和Spring一同工作的时候,AOP事务管理不起作用的解决方法
- 学习Java框架的笔记(Spring AOP)基于代理类的AOP实现、AspectJ开发(2)、ApectJ注解式声明
- springMVC学习笔记---day02 springMVC+spring+mybatis整合开发框架搭建
- Spring学习笔记----三大框架(Spring+SpringMVC+MyBatis)整合详细教程
- ITCAST视频-Spring学习笔记(使用Spring的注解方式实现AOP的细节)
- Spring+Spring MVC+MyBatis实现SSM框架整合详细教程
- maven+spring+springmvc+mybatis+ajax 框架下实现简单的聊天室
- Spring+Spring MVC+MyBatis实现SSM框架整合详细教程【转】
- J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现
- 框架学习之Spring 第三节 采用Spring实现AOP功能
- ITCAST视频-Spring学习笔记(使用Spring的注解方式实现AOP入门)
- Spring源码学习笔记(三)AOP实现