OOP (Object Oriented Programming) 面向对象编程
AOP (Aspect Oritented Programming) 面向切面编程)
两者不是替代的关系而是互补的,AOP主要就是在不改变原本代码功能的情况下去新增功能
在spring中AOP很重要,可以理解为,AB业务互不影响且要去实现C的业务,但是我们需要在执行A业务的时候,在C业务功能的基础上,让A业务完成想要的功能,让B业务完成B业务需要的更强大的功能,前提就是C业务是基础业务是不能被更改的,不然就要影响其他业务。
所以在这个时候,AOP就做出了一个动作,A业务在C业务的想要添加的方法前面砍断,添加一个新的A自己的业务上去后,再将重新组合好的业务给织入原来的C业务方法那里去,继续执行C业务后面的功能。B业务一样的。
org.springframework spring-aop 5.3.18
org.aspectj aspectjrt 1.9.6 runtime
org.springframework spring-aspects 5.3.18
最主要的就是加上了:
xmlns:aop="http://www.springframework.org/schema/aop"http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xs
注意:使用AOP的话是需要开启动态代理的哈,proxy-target-class的值true代表jdk实现,false代表cglib实现
开始创建切入类
//放入spring中
@Component
@Aspect //这个标签是标记这个类是一个切面
public class PetAspect {/*** 标记再哪里什么时候执行切入* @param joinPoint*/// execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍@Before("execution(public com.xiaowang.entity.User com.xiaowang.PetService.impl.PetServiceImpl.login(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("before之前执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}
}
执行结果:
我们可以看到,就在login方法的前面就添加进去了我们的对象的方法,我们拦截的东西也可以看到了,这里同时还有多种类似于@before的注解,其功能就是在这个方法切入点的哪一个位置进行切入,例如还有:
/*** 标记再哪里什么时候执行切入,* @befor 代表在标记位置的前面切入* @param joinPoint*/// execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍@Before("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("before之前执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** @After 在切入点的后面切入方法功能进去* 相当于finally执行,就是必备执行* @param joinPoint*/@After("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void after(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("after执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** @AfterReturning 相当于正常执行,就是拦截方法正确执行后就可以执行* @param joinPoint*/@AfterReturning("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void afterReturning(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("afterReturning执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** 拦截的语句那里抛出异常后被执行* @param joinPoint*/@AfterThrowing("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void afterThrowing(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("afterThrowing执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}
①拦截方法正常执行的时候结果:
②拦截方法有异常的时候结果:
如果使用AOP去管理事务的话,那我们就可以在before里面写事务的开启,在afterReturning中提交事务,在afterThrowing中去回滚事务,
所以在@afterThrowing这里的话就可以再加一点属性,去设置哪些地方需要回滚,哪些地方不需要回滚
/*** 拦截的语句那里抛出异常后被执行,相当于catch* @param joinPoint*/@AfterThrowing(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))",throwing = "e")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void afterThrowing(JoinPoint joinPoint,Exception e){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("afterThrowing执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());//事务System.out.println("抛出异常进行回滚"+e.getMessage());}
独特的环绕执行:
/*** 环绕执行,就像过滤器一样,再dofilt前面执行,后面执行* @param proceedingJoinPoint* @return*/@Around(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public Object around(ProceedingJoinPoint proceedingJoinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("around之前执行");Object proceed = proceedingJoinPoint.proceed();//代理的方法执行System.out.println("around之后执行");return proceed;}
使用xml实现当然前期的依赖呀、配置文件的头部那些基本的都是要有哈,和注解实现的前面一样,区别就在于对切面类的编写的时候,切入点不用写在注解上了,而是写在xml文件里了,也就是删掉or注释掉切面类中的注解呀
//放入spring中
@Component
@Aspect //这个标签是标记这个类是一个切面
public class PetAspect {/*** 标记再哪里什么时候执行切入,* @befor 代表在标记位置的前面切入* @param joinPoint*/// execution:里面写的就是切入点,切入点有很多种语法,下面这个是最精准的切入点,直接定位到了具体的方法,切入点的语法有很多,下面一一介绍// @Before("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void before(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("before之前执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** @After 在切入点的后面切入方法功能进去* 相当于finally执行,就是必备执行* @param joinPoint*/// @After("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void after(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("after执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** @AfterReturning 相当于正常执行,就是拦截方法正确执行后就可以执行* @param joinPoint*/// @AfterReturning("execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void afterReturning(JoinPoint joinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("afterReturning执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());}/*** 拦截的语句那里抛出异常后被执行,相当于catch* @param joinPoint*/// @AfterThrowing(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))",throwing = "e")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public void afterThrowing(JoinPoint joinPoint,Exception e){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("afterThrowing执行");System.out.println("拦截的参数为:"+ Arrays.toString(joinPoint.getArgs()));System.out.println("拦截的方法为:"+joinPoint.getSignature().getDeclaringTypeName() + joinPoint.getSignature().getName());System.out.println("拦截的位置为:"+joinPoint.getStaticPart());System.out.println("代理对象为:"+joinPoint.getThis());System.out.println("目标对象为:"+joinPoint.getTarget());//事务System.out.println("抛出异常进行回滚"+e.getMessage());}/* *//*** 环绕执行,就像过滤器一样,再dofilt前面执行,后面执行* @param proceedingJoinPoint* @return*//*//@Around(value = "execution(public com.xiaowang.entity.Pet com.xiaowang.dao.impl.PetDaoImpl.add(java.lang.String,java.lang.String))")//想将下面这个方法切入到测试类中testJDK()方法的前面执行public Object around(ProceedingJoinPoint proceedingJoinPoint){//JoinPoint参数是切入点的意思,具体的切入点通过before注解去填写就行//切入面中,是可以获取很多被拦截的东西,System.out.println("around之前执行");Object proceed = proceedingJoinPoint.proceed();//代理的方法执行System.out.println("around之后执行");return proceed;}
*/
}
注意:我们在切面类上面加了@Aspect 这个注解后,就代表着这是一个切面了,就不用在xml中去通过
xml配置文件:
直接精准到一个方法上面去
execution( public com.zlt.entity.User com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意权限修饰符
execution( com.zlt.entity.User com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
无返回类型
execution( void com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
有返回类型
execution( !void com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意返回类型
execution( * com.zlt.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))
任意参数
execution( * com.zlt.service.impl.UserServiceImpl.login(..))
类中的任意方法
execution( * com.zlt.service.impl.UserServiceImpl.*(..))
类中以指定内容开头的方法
execution( * com.zlt.service.impl.UserServiceImpl.select*(..))
包中的任意类的任意方法不包含子包下面的类
execution( * com.zlt.service.impl.*.*(..))
包中及其下的任意类的任意方法
execution( * com.zlt.service..*.*(..))
上一篇:第十三章 项目合同管理