1、概述
- AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程
- AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2、原理以及优势
对原有【纵向】的代码,【横向】植入【内容】的对原有的代码进行【影响】
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
3、实现(配置文件方式和注解方式)
几个专业的名字,如图所示进行解释:
Spring中自定义的5个增强类型
增强/通知类型 | 实现接口 | 描述 |
---|---|---|
前置增强 | org.springframework.aop.BeforeAdvice | 目标方法执行前实施增强 |
后置增强 | org.springframework.aop.AfterReturningAdvice | 在目标方法执行后实施增强 |
环绕增强 | org.aopalliance.intercept.MethodInterceptor | 在目标方法执行前后实施增强 |
异常抛出增强 | org.springframework.aop.ThrowsAdvice | 在目标方法抛出异常后实施增强 |
引介增强 | org.springframework.aop.IntroductionInterceptor | 在目标类中添加一些新的方法和属性 |
3.1 xml实现一
step1:定义目标对象
UserService.java
package com.tc.service;
public interface UserService {
public void addUser();
public void deleteUser();
}
UserServerImp.java
public class UserServiceImp implements UserService {
public void addUser() {
System.out.println("添加了一个user");
}
public void deleteUser() {
System.out.println("删除了一个user");
}
}
step2:定义切面以及增强/通知
切面A:前置增强/通知——MethodBeforeAdvice
public class Log implements MethodBeforeAdvice {
/**
* method:目标对象的方法
* objects:参数
* o:目标对象
*
*/
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了,参数为"+objects.toString());
}
}
切面B:后置增强/通知——AfterReturningAdvice
public class AfterLog implements AfterReturningAdvice {
/**
* o:返回值
* method:目标对象的方法
* objects:参数
* o1:目标对象
*
*/
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置增强:执行了"+o1.getClass().getName()+"的"+method.getName()+"方法,返回值为:"+o);
}
}
step3:Bean注入
<!--加载类到spring-->
<bean id="userService" class="com.tc.service.UserServiceImp"></bean>
<bean id="beforeLog" class="com.tc.aspect.BeforeLog"></bean>
<bean id="afterLog" class="com.tc.aspect.AfterLog"></bean>
step4:定义连接点,以及切入点
1、execution(): 表达式主体 (必须加上execution)。
2、第一个*号:表示返回值类型,*号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,cn.smd.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
书写的注意事项:execution(* cn.smd.service.impl.*.*(..))
<!--配置aop-->
<aop:config>
<!--定义切入点-->
<aop:pointcut id="logAspect" expression="execution(* com.tc.service.UserService.*(..))"/>
<!--定义连接点-->
<!--前置通知/增强-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="logAspect" ></aop:advisor>
<!--后置通知/增强-->
<aop:advisor advice-ref="afterLog" pointcut-ref="logAspect" ></aop:advisor>
</aop:config>
step5:调用测试
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)applicationContext.getBean("userService");
userService.addUser();
输出:
3.2 xml实现二
step1:定义目标对象,同上
step2:定义切面以及通知/增强定义
不需要实现任何接口,只是一个普通的类,类里面包括多个方法
public class commonAspect {
public void beforeFunc(){
System.out.println("前置增强");
}
public void afterFunc(){
System.out.println("后置增强");
}
}
step3:切入点以及连接点定义
<!--定义切面-->
<aop:aspect ref="commonAspect">
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.tc.service.UserServiceImp.*(..))" ></aop:pointcut>
<!--定义增强-->
<aop:before method="beforeFunc" pointcut-ref="point"></aop:before>
<aop:after method="afterFunc" pointcut-ref="point"></aop:after>
</aop:aspect>
3.3 注解实现
切面,通知/增强,切入点,连接点都在类中定义
@Aspect
public class annoAspect {
@Before("execution(* com.tc.service.UserServiceImp.*(..))")
public void beforeFunc(){
System.out.println("前置增强----");
}
@After("execution(* com.tc.service.UserServiceImp.*(..))")
public void afterFunc(){
System.out.println("后置增强");
}
@Around("execution(* com.tc.service.UserServiceImp.*(..))")
public void aroundFunc(ProceedingJoinPoint process) throws Throwable {
System.out.println("环绕增强前");
Object obj = process.proceed();// 执行模板方法
System.out.println("环绕增强后");
}
}
@Aspet定义切面,相当于:
<bean id="commonAspect" class="com.tc.aspect.commonAspect"></bean>
<aop:aspect ref="commonAspect">
xxxx
</aop:aspect>
@Before("execution(* com.tc.service.UserServiceImp.*(..))")注解中的内容,为定义连接点,相当于:
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.tc.service.UserServiceImp.*(..))" ></aop:pointcut>
@Before,@After,@around...定义切入点,相对于:
<!--定义连接点-->
<aop:before method="beforeFunc" pointcut-ref="point"></aop:before>
<aop:after method="afterFunc" pointcut-ref="point"></aop:after>