AOP的概念
AOP(Aspect Oriented Programming),即面向切面编程,利用一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
AOP开发术语
- 连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
- 切入点(Pointcut):被Spring切入连接点。
- 通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。
- 目标对象(Target):代理的目标对象
- 引介(Introduction):一种特殊的增强,可在运行期为类动态添加Field和Method。
- 织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。
- 代理(Proxy):被AOP织入通知后,产生的结果类。
- 切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
AOP增强类
前置增强:MethodBeforeAdvice
后置增强:AfterAdvice
后置增强:AfterReturningAdvice
异常增强:ThrowsAdvice
环绕增强:MethodInterceptor
切入点表达式
匹配包名:execution(* com.robot.service.* .*(…))
- 返回值任意,com.robot.service包下面的任意类,下面的任意方法,参数任意
<!--匹配参数-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.robot.pojo.User))" />
<!--匹配方法名(无参)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--匹配方法名(任意参数)-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--匹配返回值类型-->
<aop:pointcut id="myPointCut" expression="execution(com.robot.pojo.User *(..))" />
<!--匹配类名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot.service.userService.impl.UserServiceImpl.*(..))" />
<!--匹配包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot.service.*.*(..))" />
<!--匹配包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.robot..*.*(..))" />
AOP的实现
1、环境搭建
导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
在配置文件中引入AOP命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
</beans>
2、创建切面类
- 以后置增强为例
- 基础AfterReturningAdvice接口,重写afterReturning方法
public class MyAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置增强:" + method.getName() + " 增强方法:" + o.getClass().getSimpleName());
}
}
3、创建需要被增强的类和接口
- 将要实现的效果就是,在调用此方法时,此方法会被增强
public interface UserDao {
int insert();
}
public class UserDaoImpl implements UserDao {
public int insert() {
System.out.println("UserDaoImpl::insert...");
return 0;
}
}
4、修改配置文件
- 配置aop,expression为切入点表达式
- 具体行为execution(* com.robot.service.* .*(…)):返回值任意,com.robot.service包下面的任意类,下面的任意方法,参数任意
<bean name="userService" class="com.robot.service.impl.UserServiceImpl"/>
<bean name="myAfterAdvice" class="com.robot.aop.MyAfterAdvice"/>
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(* com.robot.service.*.*(..))"/>
<aop:advisor advice-ref="myAfterAdvice" pointcut-ref="myPointcut"/>
</aop:config>
5、测试
- 调用service层中的方法
public class UserServiceTest {
@Test
public void userServiceTest() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.insert();
}
}
结果如下
UserDaoImpl::insert...
后置增强:insert 增强方法:Integer
在被调用的insert()方法的后面切入了增强方法,输出了方法内的语句,说明方法增强成功
总结
-
通过AOP提供的编码流程,更便利的定制切面,更方便的定制了动态代理。
-
进而彻底解决了辅助功能冗余的问题;
-
业务类中职责单一性得到更好保障;
-
辅助功能也有很好的复用性。