Spring Aop 功能实现

Aop:指程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。

基于注解的Aop 实现步骤:

  1. 1、导入aop模块;Spring AOP:(spring-aspects)
  2. 2、定义一个业务逻辑类(UserServiceImpl);在业务逻辑运行的时候将日志进行打印包括在(方法运行的之前,运行结束,运行异常等)
  3. 3、定义一个日志切面类(LogAspect):切面类里面的方法需要动态感知UserServiceImpl运行到哪里然后执行;
  4. 通知方法:
  5. 前置通知(``@Before``):logStart:在目标方法运行之前运行
  6. 后置通知(``@After``):logEnd:在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
  7. 返回通知(``@AfterReturning``):logReturn:在目标方法正常返回之后运行
  8. 异常通知(``@AfterThrowing``):logException:在目标方法出现异常以后运行
  9. 环绕通知(``@Around``):动态代理,手动推进目标方法运行。
  10. 4、给切面类的目标方法标注何时何地运行(通知注解);
  11. 5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
  12. 6、必须告诉Spring哪个类是切面类(@Aspect)
  13. 7、给配置类中加 @EnableAspectJAutoProxy

Aop 的注解代码实现:

导入spring-aspects的jar包:

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-aspects</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

业务类(UserServiceImpl)

  1. public class UserServiceImpl {
  2. public String loginUser(String username,String password) {
  3. System.out.println("用户登录成功~~~~~~~");
  4. return "登录成功";
  5. }
  6. }

在定义切面之前我们说一下Aspectj切入点语法定义

在我们使用Spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义切入点(Pointcut)。

例如定义切入点表达式 *execution ( zfcoding.service..*.(..))

execution()是最常用的切点函数,其语法如下所示:

整个表达式可以分为五个部分:

  • execution(): 表达式主体。
  • 第一个号:表示返回类型,号表示所有的类型。
  • 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,zfcoding.service.包、子包下所有类的方法。
  • 第二个号:表示类名,号表示所有的类。
  • (..):最后这个星号表示方法名,号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

切面类(LogAspect)

  1. @Aspect
  2. public class LogAspect {
  3. //定义切面的执行规规则
  4. @Pointcut("execution (* zfcoding.service..*.*(..))")
  5. public void pointCut() {
  6. }
  7. @Before("pointCut()")
  8. public void logStart() {
  9. System.out.println("登录开始通知");
  10. }
  11. @After("pointCut()")
  12. public void logEnd() {
  13. System.out.println("登录结束通知");
  14. }
  15. @AfterReturning("pointCut()")
  16. public void logReturn() {
  17. System.out.println("返回通知");
  18. }
  19. @AfterThrowing("pointCut()")
  20. public void logException() {
  21. System.out.println("异常通知");
  22. }
  23. }

将业务类和切面类注入到Spring容器当中,使用@EnableAspectJAutoProxy开启注解的Aop 功能

  1. @Configuration //配置类
  2. @EnableAspectJAutoProxy //开启注解的Aop 功能
  3. public class MyConfigAspect {
  4. @Bean //bean注入到Spring容器当中
  5. public UserServiceImpl userService() {
  6. return new UserServiceImpl();
  7. }
  8. @Bean
  9. public LogAspect logAspect() {
  10. return new LogAspect();
  11. }
  12. }

测试类:

  1. public class AspectTest {
  2. @Test
  3. public void test(){
  4. AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigAspect.class);
  5. UserServiceImpl bean = applicationContext.getBean(UserServiceImpl.class);
  6. bean.loginUser("admin","123");
  7. }
  8. }

运行结果:

  1. 登录开始通知
  2. 用户登录成功~~~~~~~
  3. 登录结束通知
  4. 返回通知

注解实现Aop 小结

  • 将业务逻辑组件和切面类都加入到容器中;并告诉Spring哪个是切面类(@Aspect
  • 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
  • 开启基于注解的aop模式;@EnableAspectJAutoProxy

基于Xml的Aop 的实现步骤

首先需要也是需要定义一个业务类和一个配置类,然后定义一个配置类,配置类实现的功能主要是将业务类和切面类注入到Spring容器当中,定义一些切面的配置。

基于Xml的Aop 代码实现:

业务类和上面注解实现一样,同上

切面类

  1. public class LogAspectXml {
  2. public void logStart() {
  3. System.out.println("登录开始通知");
  4. }
  5. public void logEnd() {
  6. System.out.println("登录结束通知");
  7. }
  8. public void logReturn() {
  9. System.out.println("返回通知");
  10. }
  11. public void logException() {
  12. System.out.println("异常通知");
  13. }
  14. }

配置类:

  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 http://www.springframework.org/schema/beans/spring-beans.xsd
  6. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  7. <!--注入bean-->
  8. <bean id="logAspectXml" class="zfcoding.aop.LogAspectXml"></bean>
  9. <bean id="userServiceImplXml" class="zfcoding.service.UserServiceImplXml"></bean>
  10. <aop:config>
  11. <aop:aspect ref="logAspectXml">
  12. <aop:pointcut id="pointCut" expression="execution (* zfcoding.service..*.*(..))"/>
  13. <aop:before method="logStart" pointcut-ref="pointCut"></aop:before>
  14. <aop:after method="logEnd" pointcut-ref="pointCut"></aop:after>
  15. <aop:after-returning method="logReturn" pointcut-ref="pointCut"></aop:after-returning>
  16. <aop:after-throwing method="logException" pointcut-ref="pointCut"></aop:after-throwing>
  17. </aop:aspect>
  18. </aop:config>
  19. </beans>

测试类

  1. public class AspectTestXml {
  2. @Test
  3. public void test(){
  4. ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-aop-xml.xml");
  5. UserServiceImplXml userServiceImplXml =(UserServiceImplXml) applicationContext.getBean("userServiceImplXml");
  6. userServiceImplXml.loginUser("aa","aa");
  7. }
  8. }

运行结果

登录开始通知 用户登录成功~~~ 登录结束通知 返回通知

Xml 实现Aop 小结

  • 将业务逻辑组件和切面类都加入到容器中;并告诉Spring哪个是切面类(
  • 定义切入点表达式,在切面类上的每一个通知方法上通过pointcut-ref标注,告诉Spring何时何地运行。