Spring AOP
首先需要了解springAOP的一些重要概:
1.切点:定义的就是为哪些方法增加功能
2.通知:定义的就是何时何事
3.切面: 切面是一个类,包含了切点和通知的类
4.织入:把切面整合到目标类的过程
5.接入点:里面保存着当前执行的方法的信息
springAOP利用了AspectJ个框架的配置方式.,就是里面的注解所以需要先导入一个jar包.
具体实现:
1.创建一个类,并spring注解标记.里面写原来执行的功能.
@Service public class BookSericeImpl implements BookSerice { @Override public void addOne(BokBean bokBean) { System.out.println("执行逻辑:插入一本书"); } @Override public void deletOne(Long bookId) { System.out.println("执行逻辑:删除一本书"); //睡眠1秒 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
2.创建一个切面,即一个类,用@Aspect注解把这个类标记为切面,
切点: 在切面里面为指定的类的方法添加切点.
通知: 在围绕切点选择想要在什么时候增强什么功能.
@Aspect @Component public class LogAspect { //1.切点 //切点实际上就是一个表达式,规定为哪些方法做增强的表达式 //表示Service类中的所有方法 @Pointcut("execution(* com.lanou.demo.service.impl.*.*(..))") public void allServiceMethod(){ } //2.通知 //前置通知 @Before("allServiceMethod()") //该注解默认等于 @Before(value = "allServiceMethod()") public void before(JoinPoint jp){ //JoinPoint接入点: // 可以根据需要获取下面的相关信息 //获取被代理对象 Object target = jp.getTarget(); //获取方法签名 Signature signature = jp.getSignature(); //获取方法的参数 Object[] args = jp.getArgs(); System.out.println("方法之前执行"); } //后置通知 @After("allServiceMethod()") public void after(JoinPoint jp){ System.out.println("方法执行后"); } //方法正常执行的通知 //returning参数:接受参数 @AfterReturning(value = "allServiceMethod()",returning = "value") public void returnLog(JoinPoint jp,Object value){ System.out.println("方法正常执行"+value); } //异常通知 @AfterThrowing(value = "allServiceMethod()",throwing = "ex") public void throwLog(JoinPoint jp,Exception ex){ System.out.println("方法异常了"); } //环绕通知 :相当于在原来方法周围添加功能. //ProceedingJoinPoint 是JoinPoint 的子类 @Around("allServiceMethod()") public Object around(ProceedingJoinPoint jp){ try { long start = System.currentTimeMillis(); //写在原来方法的前面相当于前置通知 Object proceed = jp.proceed(); //这是执行的原来的方法 long time = System.currentTimeMillis()-start; //写在原来方法后面相当于后置通知 System.out.println("运行时长"+time); return proceed; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; } }
3.创建好切面后,需要在spring配置文件中配置aop,让spring根据注解自动加载切面
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.lanou.demo"/> <mvc:annotation-driven/> <aop:config> <aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/> <aop:aspect ref="logAspect" order="1"> <aop:before method="before" pointcut-ref="service"/> </aop:aspect> </aop:config> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <!--配置可以根据注解自动加切面的功能--> <!--第一种的配置方式:常用-->
<aop:aspectj-autoproxy/>
<!--第二种配置方式: 这种配置方式不需要再用注解标记,而是在这里面指定要加载的类和方法 里面的参数跟注解方式注解的参数对应. --> <!--<aop:config>--> <!--<aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/>--> <!--<aop:aspect ref="logAspect" order="1">--> <!--<aop:before method="before" pointcut-ref="service"/>--> <!--</aop:aspect>--> <!--</aop:config>--> </beans>
4.调用bookserviceImpl中的方法,(这里用spring测试类测试)
//spring测试类注解. @RunWith(SpringJUnit4ClassRunner.class) //加载spring的配置文件 @ContextConfiguration("classpath:application-context.xml") public class BookSericeImplTest { @Resource private BookSerice bookSerice; @Test public void text1() {
//调用原来方法 this.bookSerice.deletOne(33L); } }
执行结果如下:
会发现为类或方法配置好切点后,当执行该方法时,spring会自动为该方法添加增强的功能.
INFO: HV000001: Hibernate Validator 6.0.16.Final
方法之前执行
执行逻辑:删除一本书
运行时长1002
方法执行后
方法正常执行null
Process finished with exit code 0