Spring Aop 功能实现
Aop:指程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。
基于注解的 Aop 实现步骤:
1、导入 aop 模块;Spring AOP:(spring-aspects)
2、定义一个业务逻辑类(UserServiceImpl);在业务逻辑运行的时候将日志进行打印包括在(方法运行的之前,运行结束,运行异常等)3、定义一个日志切面类(LogAspect):切面类里面的方法需要动态感知 UserServiceImpl 运行到哪里然后执行;通知方法:前置通知(``@Before``):logStart:在目标方法运行之前运行
后置通知(``@After``):logEnd:在目标方法运行结束之后运行(无论方法正常结束还是异常结束)返回通知(``@AfterReturning``):logReturn:在目标方法正常返回之后运行
异常通知(``@AfterThrowing``):logException:在目标方法出现异常以后运行
环绕通知(``@Around``):动态代理,手动推进目标方法运行。4、给切面类的目标方法标注何时何地运行(通知注解);5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
6、必须告诉 Spring 哪个类是切面类(@Aspect)
7、给配置类中加 @EnableAspectJAutoProxy
Aop 的注解代码实现:
导入 spring-aspects 的 jar 包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
业务类(UserServiceImpl)
public class UserServiceImpl {public String loginUser(String username,String password) {System.out.println("用户登录成功~~~~~~~");
return "登录成功";
}
}
在定义切面之前我们说一下Aspectj 切入点语法定义
在我们使用 Spring 框架配置 AOP 的时候,不管是通过 XML 配置文件还是注解的方式都需要定义切入点(Pointcut)。
例如定义切入点表达式 execution (* zfcoding.service..*.*(..))
execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
- execution(): 表达式主体。
- 第一个 * 号:表示返回类型,* 号表示所有的类型。
- 包名:表示需要拦截的包名,后面的 两个句点 表示当前包和当前包的所有子包,zfcoding.service. 包、子包下所有类的方法。
- 第二个 * 号:表示类名,* 号表示所有的类。
- *(..): 最后这个星号表示方法名,* 号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
切面类(LogAspect)
@Aspect
public class LogAspect {
// 定义切面的执行规规则
@Pointcut("execution (* zfcoding.service..*.*(..))")
public void pointCut() {}
@Before("pointCut()")
public void logStart() {System.out.println("登录开始通知");
}
@After("pointCut()")
public void logEnd() {System.out.println("登录结束通知");
}
@AfterReturning("pointCut()")
public void logReturn() {System.out.println("返回通知");
}
@AfterThrowing("pointCut()")
public void logException() {System.out.println("异常通知");
}
}
将业务类和切面类注入到 Spring 容器当中, 使用 @EnableAspectJAutoProxy 开启注解的 Aop 功能
@Configuration // 配置类
@EnableAspectJAutoProxy // 开启注解的 Aop 功能
public class MyConfigAspect {
@Bean //bean 注入到 Spring 容器当中
public UserServiceImpl userService() {return new UserServiceImpl();
}
@Bean
public LogAspect logAspect() {return new LogAspect();
}
}
测试类:
public class AspectTest {
@Test
public void test(){AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigAspect.class);
UserServiceImpl bean = applicationContext.getBean(UserServiceImpl.class);
bean.loginUser("admin","123");
}
}
运行结果:
登录开始通知
用户登录成功~~~~~~~
登录结束通知
返回通知
注解实现 Aop 小结
- 将业务逻辑组件和切面类都加入到容器中;并告诉 Spring 哪个是切面类(
@Aspect
) - 在切面类上的每一个通知方法上标注通知注解,告诉 Spring 何时何地运行(切入点表达式)
- 开启基于注解的 aop 模式;@EnableAspectJAutoProxy
基于 Xml 的 Aop 的实现步骤
首先需要也是需要定义一个业务类和一个配置类,然后定义一个配置类,配置类实现的功能主要是将业务类和切面类注入到 Spring 容器当中,定义一些切面的配置。
基于 Xml 的 Aop 代码实现:
业务类和上面注解实现一样,同上
切面类
public class LogAspectXml {public void logStart() {System.out.println("登录开始通知");
}
public void logEnd() {System.out.println("登录结束通知");
}
public void logReturn() {System.out.println("返回通知");
}
public void logException() {System.out.println("异常通知");
}
}
配置类:
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注入 bean-->
<bean id="logAspectXml" class="zfcoding.aop.LogAspectXml"></bean>
<bean id="userServiceImplXml" class="zfcoding.service.UserServiceImplXml"></bean>
<aop:config>
<aop:aspect ref="logAspectXml">
<aop:pointcut id="pointCut" expression="execution (* zfcoding.service..*.*(..))"/>
<aop:before method="logStart" pointcut-ref="pointCut"></aop:before>
<aop:after method="logEnd" pointcut-ref="pointCut"></aop:after>
<aop:after-returning method="logReturn" pointcut-ref="pointCut"></aop:after-returning>
<aop:after-throwing method="logException" pointcut-ref="pointCut"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
测试类
public class AspectTestXml {
@Test
public void test(){ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-aop-xml.xml");
UserServiceImplXml userServiceImplXml =(UserServiceImplXml) applicationContext.getBean("userServiceImplXml");
userServiceImplXml.loginUser("aa","aa");
}
}
运行结果
登录开始通知
用户登录成功~~~
登录结束通知
返回通知
Xml 实现 Aop 小结
- 将业务逻辑组件和切面类都加入到容器中;并告诉 Spring 哪个是切面类(<aop:aspect ref=”logAspectXml”>)
- 定义切入点表达式,在切面类上的每一个通知方法上通过 pointcut-ref 标注,告诉 Spring 何时何地运行。
我是阿福,公众号「阿福聊编程」作者,对后端技术保持学习爱好者,我会经常更新 JAVA 技术文章,在进阶的路上,共勉!
欢迎大家关注我的公众号,后台回复666,领取福利,你懂的。