如何使用Spring的Schema配置切面?
废话不多说,直接通过一个Demo来看一下吧,这里我们需要将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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:before method="preGreeting" pointcut="target(com.zheng.demo7.NaiveWaiter) and execution(* greetTo(..))"/>
</aop:aspect>
</aop:config>
<bean id="adviceMethod" class="com.zheng.demo7.AdviceMethod"></bean>
<!-- 目标bean -->
<bean id="waiter" class="com.zheng.demo7.NaiveWaiter"></bean>
</beans>
增强类AdviceMethod:
public class AdviceMethod {
// 增强方法
public void preGreeting()
{
System.out.println("How are you!");
}
}
场景调用如下:
public class Client {
public static void main(String[] args) {
String path = "com/zheng/demo7/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(path);
Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("John");
}
}
输出了我们想要的效果:
How are you!
waiter greet to John
配置命名切点
上面的spring配置虽然完成了我们想要的效果,但是如果我们想要对该切点在一个切面中的不同增强进行重用怎么办呢?spring的aop配置可以声明切点,如下:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:pointcut id="greetToPointcut" expression="target(com.zheng.demo7.NaiveWaiter) and execution(* greetTo(..))"/>
<aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
</aop:aspect>
</aop:config>
如果希望可以在不同切面进行重用怎么办?如下:
<aop:config proxy-target-class="true">
<aop:pointcut id="greetToPointcut" expression="target(com.zheng.demo7.NaiveWaiter) and execution(* greetTo(..))"/>
<aop:aspect ref="adviceMethod">
<aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
</aop:aspect>
<aop:aspect ref="adviceMethod1">
<aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
</aop:aspect>
</aop:config>
各种增强类型的配置方法
前置增强已经说过,就不在提了,下面其他类增强配置方法如下:
后置增强
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:after-returning method="afterReturning" pointcut="target(com.zheng.demo8.NaiveWaiter)" returning="retVal"/>
</aop:aspect>
</aop:config>
<bean id="adviceMethod" class="com.zheng.demo8.AdviceMethod"></bean>
returning标签为被增强方法的返回值,注意这个参数的名字必须跟增强的方法的入参名字保持一致。如下:
public class AdviceMethod {
// 增强方法
public void afterReturning(int retVal)
{
System.out.println("bye bye!");
System.out.println("the returning is " + retVal);
}
}
环绕增强
aop配置如下:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:around method="aroundMethod"
pointcut="execution(* greetTo(..)) and within(com.zheng.demo9.NaiveWaiter)"/>
</aop:aspect>
</aop:config>
增强方法如下:
public class AdviceMethod {
// 增强方法
public void aroundMethod(ProceedingJoinPoint pjp)
{
// 目标方法执行前的逻辑
System.out.println("How are you!");
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
// 目标方法执行后的逻辑
System.out.println("Bye bye!");
}
}
抛出异常增强
aop配置:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:after-throwing method="afterThrowingMethod"
pointcut="target(com.zheng.demo10.NaiveWaiter) and execution(* greetTo(..))"
throwing="iae"/>
</aop:aspect>
</aop:config>
其中throwing="iae"对应增强方法的入参,异常的类型。增强方法如下:
public class AdviceMethod {
// 增强方法
public void afterThrowingMethod(IllegalArgumentException iae)
{
// 捕获异常的逻辑
}
}
Final增强
aop配置:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:after method="afterMethod"
pointcut="execution(* greetTo(..))"/>
</aop:aspect>
</aop:config>
增强方法如下:
public class AdviceMethod {
// 增强方法
public void afterMethod()
{
// Final增强的逻辑
}
}
引介增强
引介增强比较特殊,aop配置如下:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:declare-parents types-matching="com.zheng.demo12.Waiter+"
default-impl="com.zheng.demo12.SmartSeller"
implement-interface="com.zheng.demo12.Seller"/>
</aop:aspect>
</aop:config>
type-matching定义的是需要引介接口实现类型bean
impelment-interface定义引介增强需要实现的接口
default-impl定义需要实现的接口实现的业务逻辑
这样上层模块就可以通过以下的方式去调用。如下:
public class Client {
public static void main(String[] args) {
String path = "com/zheng/demo12/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(path);
Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("John");
((Seller)waiter).sell("food");
}
}
从而实现waiter类实现了seller接口的方法。
绑定连接点信息
aop的Schema配置中绑定连接点信息的方法如下:
第一,所有增强类型对应的方法第一个入参都可以声明为JoinPoint。(环绕增强可声明为ProceedingJoinPoint)访问连接点信息。
第二,后置增强通过(<aop:after-returning>)returing属性绑定返回值信息,抛出异常增强通过throwing属性访问连接点方法所抛出的异常。
第三,所有增强方法都可以通过绑定参数的切点函数绑定连接方法的入参。举例如下:
aop配置如下:
<aop:config proxy-target-class="true">
<aop:aspect ref="adviceMethod">
<aop:before method="bindParams"
pointcut="target(com.zheng.demo13.NaiveWaiter) and args(name,num,..)"/>
</aop:aspect>
</aop:config>
增强方法的方法入参名字必须和配置的一致,如下:
public class AdviceMethod {
// 增强方法
public void bindParams(int num, String name)
{
System.out.println("name : " + name);
System.out.println("num : " + num);
}
}
Advisor配置
advisor对应于spring中的切面概念,它包含一个切点和增强。基本配置跟aspect的切面配置类似,如下:
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="beforAdvice"
pointcut="target(com.zheng.demo14.NaiveWaiter) and execution(* greetTo(..))"/>
</aop:config>
<bean id="beforAdvice" class="com.zheng.demo14.AdviceMethod"></bean>
增强方法如下:
public class AdviceMethod implements MethodBeforeAdvice{
public void before(Method method, Object[] args, Object obj)
throws Throwable {
System.out.println("clientName : " + args[0]);
}
}
到此,关于Spring的Schema配置基本用法就讲完了,通过这一章的学习,感觉Spring自己提供的基于Schema的配置方式比之前自己定义切面,通过注解去实现Aop的方式要简单的多了,
而且在Spring的配置文件中清晰的描述出了横切关系,便于管理,不得不说我个人非常喜欢这种方式,简单实用