1.声明schema,导入命名空间
(1)如果我们想要使用基于xml的spring aop,那么,第一步,我们需要在xml配置文件中声明spring aop schema,导入命名空间,如下这是一个标准的模板
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- //... -->
</beans>
(2)在xml配置文件中,所有的切面以及通知等都必须放置于<aop:config>标签内
2.声明一个切面
//定义一个切面类Logger,在其中声明一个前置通知
public class Logger {
public void beforePrint() {
System.out.println("before...");
}
}
<!-- xml配置文件 -->
<beans ....>
<!-- 将切面类注册为spring的一个bean -->
<bean id="logger" class="cn.example.spring.boke.Logger"></bean>
<aop:config>
<!-- 使用<aop:aspect>标签,来定义一个切面,其中id的值需唯一,ref用来引用切面类 -->
<aop:aspect id="aspect" ref="logger">
<!-- 在<aop:aspect>标签内部,我们可以定义5种通知,在这里使用<aop:before>标签来定义一个前置通知,其中method指定通知方法,它只能是Logger这个切面类中的方法,pointcut指定切入点表达式 -->
<aop:before method="beforePrint" pointcut="execution(* cn.example.spring.boke.ExampleA.*(..))"></aop:before>
</aop:aspect>
</aop:config>
</beans>
3.声明一个切入点
<beans ....>
<bean id="logger" class="cn.example.spring.boke.Logger"></bean>
<aop:config>
<!-- 使用<aop:pointcut>标签来定义一个切入点,其中id的值唯一,expression即为切入点表达式 -->
<!-- 之后,在通知标签内部,使用pointcut-ref来引用这个切入点 -->
<aop:pointcut id="common" expression="execution(* cn.example.spring.boke.ExampleA.*(..))"/>
<!-- 在基于xml的切入点表达式中 &&, || 以及 ! 分别被替换为了 and, or 与 not,如下面这个例子 -->
<aop:pointcut id="mix" expression="execution(public * *(..)) and @args(org.springframework.stereotype.Component)"/>
<aop:aspect id="aspect" ref="logger">
<aop:before method="beforePrint" pointcut-ref="common"></aop:before>
</aop:aspect>
</aop:config>
</beans>
4.声明一个通知
//切面类
public class Logger {
public void beforePrint() {
System.out.println("before...");
}
public void afterReturningPrint(Object returnVal) {
System.out.println(returnVal);
System.out.println("afterReturning...");
}
public void afterThrowingPrint(Throwable throwable) {
System.out.println(throwable);
System.out.println("afterThrowing...");
}
public void afterPrint() {
System.out.println("after...");
}
public void aroundPrint(ProceedingJoinPoint joinPoint) {
try {
System.out.println("before...");
joinPoint.proceed();
System.out.println("after...");
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
System.out.println("finally...");
}
}
}
<aop:config>
<aop:pointcut id="common" expression="execution(* cn.example.spring.boke.ExampleA.*(..))"/>
<aop:aspect id="aspect" ref="logger">
<!-- 使用<aop:before>声明前置通知 -->
<aop:before method="beforePrint" pointcut-ref="common"></aop:before>
<!-- 使用<aop:after-returning>声明返回通知,其中使用returning属性来声明获取切入点执行后的返回值,与前面基于注解的示例相同 -->
<aop:after-returning method="afterReturningPrint" pointcut-ref="common" returning="returnVal"></aop:after-returning>
<!-- 使用<aop:after-throwing>声明异常通知,其中使用throwing属性来声明获取切入点执行异常后所抛出的异常,与前面基于注解的示例相同 -->
<aop:after-throwing method="afterThrowingPrint" pointcut-ref="common" throwing="throwable"></aop:after-throwing>
<!-- 使用<aop:after>声明后置通知 -->
<aop:after method="afterPrint" pointcut-ref="common"></aop:after>
<!-- 使用<aop:around>声明环绕通知,具体的注意事项与前面基于注解的示例相同 -->
<aop:around method="aroundPrint" pointcut-ref="common"></aop:around>
</aop:aspect>
</aop:config>
5.优先级
<beans ....>
<bean id="logger" class="cn.example.spring.boke.Logger"></bean>
<bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean>
<aop:config>
<aop:pointcut id="common" expression="execution(* cn.example.spring.boke.ExampleA.*(..))"/>
<!-- 可使用<aop:aspect/>标签中的order属性来声明不同切面类的优先级 -->
<aop:aspect id="aspect" ref="logger" order="1">
<!-- 在同一切面类中,不同切面的优先级与切面声明的顺序有关,如下由于<aop:before/>标签声明于<aop:around/>标签之前,因此before的优先级高于around -->
<aop:before method="beforePrint" pointcut-ref="common"></aop:before>
<aop:around method="aroundPrint" pointcut-ref="common"></aop:around>
</aop:aspect>
</aop:config>
</beans>
6.声明一个引介
public class ExampleA{
}
//希望向ExampleA中添加方法doSomething()
public interface Extention {
void doSomething();
}
//doSomething()方法默认的实现
public class ExtentionImpl implements Extention{
@Override
public void doSomething() {
System.out.println("doSomething...");
}
}
<beans ....>
<bean id="logger" class="cn.example.spring.boke.Logger"></bean>
<bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean>
<aop:config>
<aop:aspect id="aspect" ref="logger">
<!-- 在<aop:aspect/>标签中,使用<aop:declare-parents/>标签便可声明一个引介,其中types-matching属性值对应@DeclareParents注解中的value属性值,default-impl属性值对应@DeclareParents注解中的defaultImpl属性值,implement-interface表明父类型,与基于注解的配置一致 -->
<aop:declare-parents types-matching="cn.example.spring.boke.*" implement-interface="cn.example.spring.boke.Extention" default-impl="cn.example.spring.boke.ExtentionImpl"></aop:declare-parents>
</aop:aspect>
</aop:config>
</beans>
//使用引介,与基于注解的配置一致
Extention exampleA = (Extention)ctx.getBean("exampleA");
7.Advisors文章来源:https://www.toymoban.com/news/detail-433247.html
(1) 除了使用<aop:aspect/>标签外,我们还可以使用<aop:advisor/>标签来声明一个切面,不过使用<aop:advisor/>时,其所指向的bean必须要实现对应的Advice接口,如下文章来源地址https://www.toymoban.com/news/detail-433247.html
//若要定义前置通知,则必须实现MethodBeforeAdvice接口,其他相应的通知也有对应的接口
public class Logger implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("advisor before...");
}
}
<beans ....>
<bean id="logger" class="cn.example.spring.boke.Logger"></bean>
<bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean>
<aop:config>
<aop:pointcut id="common" expression="execution(* cn.example.spring.boke.ExampleA.*(..))"/>
<!-- 使用<aop:advisor/>标签来定义一个切面,与前面的<aop:aspect/>标签相比,不需要在其内部声明具体的通知标签了,在底层原理上,<aop:advisor/>与<aop:aspect/>是相似的,只是<aop:advisor/>的使用方式变了而已,且该标签一般专用于事物管理上 -->
<aop:advisor advice-ref="logger" pointcut-ref="common"></aop:advisor>
</aop:config>
</beans>
到了这里,关于Spring AOP官方文档学习笔记(三)之基于xml的Spring AOP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!