要使用基于Schema的AOP,IoC容器的配置文件应该使用基于Schema的XML,同时在文件投中增加针对AOP的命名空间声明,如下:
<?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-3.0.xsd"> <!--相关bean定义--> </bean>
新的基于Schema的AOP配置方式,针对Pointcut,Advisor以及Aspect等概念提供了独立的配置元素。所有这些配置元素都包含在统一的配置元素中,即<aop:config>, <aop:config> 只有一个属性proxy-target-class, 对应ProxyConfig中的proxyTargetClass属性,通过该属性可以控制使用基于类还是基于接口的动态代理。如下:
<?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-3.0.xsd"> <aop:config proxy-target-class="true"> <!--其他aop概念元素定义--> </aop:config> </beans>
<aop:config>内部可以有三个子元素,分别是<aop:pointcut>,<aop:advisor>和<aop:aspect>。它们三个必须按照顺序进行配置,代码如下:
<?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-3.0.xsd"> <aop:config proxy-target-class="false"> <aop:pointcut/> <aop:advisor/> <aop:aspect></aop:aspect> </aop:config> </beans>
另外,可以在同一个配置文件中配置多个<aop:config>.
<aop:config> 会根据元素内部对应的Pointcut,Advisor以及Aspect的子元素取得必要的织入信息,然后为容器内注册的bean进行自动代理。和使用AutoProxyCreator一样。但两者最好不要混用。
<?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-3.0.xsd"> <aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> // 1 <aop:before method="preGreeting" pointcut="target(com.ivy.NaiveWaiter) and execution(* greetTo(..))"/> // 2 </aop:aspect> </aop:config> <bean id="adviceMethods" class="com.ivy.schema.AdviceMethods"/> // 3 <bean id="naiveWaiter" class="com.ivy.NaiveWaiter"/> <bean id="naughtWaiter" class="com.ivy.NaughtyWaiter"/> </beans>
使用一个<aop:aspect>元素标签定义切面,其内部可以定义多个增强。在<aop:config>元素中可以定义多个切面。在1处,切面引用了adviceMethods Bean, 该Bean是增强方法所在的类。通过<aop:before> 声明了一个前置增强,并通过pointcut属性定义切点表达式,method属性指定增强的方法,该方法应该是adviceMethods bean中的方法。
<aop:config>拥有一个proxy-target-class属性,当设置为true时,表示其中声明的切面均使用CGLib动态代理技术;当设置为false时,使用JDK动态代理。一个配置文件可以同时定义多个<aop:config>,不同的<aop:config>可以采取不同的代理技术。
1, 基于Schema的Aspect声明
<aop:config> <aop:aspect id="myAspect" ref="schemaBasedAspect" order="2"> ... </aop:aspect> </aop:config>
2, 基于Schema的Pointcut声明
基于Schema的Pointcut声明(<aop:pointcut〉)可以位于两个位置:一个位置是直接声明到<aop:config>下面,这样的Pointcut定义可以在其余的Advisor定义和Aspect定义中共享引用,另一个位置就是<aop:aspect>元素内部,这种Pointcut只能在其所声明的<aop:aspect〉内部引用,相当于修饰符是private。
<aop:config> <aop:aspect id="myAspect" ref="schemaBasedAspect" order="2"> <aop:pointcut id="privatePointcut" expression="execution(public void *.doSth())" /> ... </aop:aspect>
</aop:config>
<bean id="shemaBasedAspect" class="...SchemaBasedAspect"></bean>
3, 基于Schema的Advice声明
在基于Schema的AOP中的Advice声明也分为两部分,Advice定义和Advice到容器中的配置。
配置命名切点
上例2处通过pointcut属性声明的切点是匿名切点,它不能被其他增强或其他切面使用,Spring提供了命名切点的配置方式:
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:pointcut expression="target(com.ivy.NaiveWaiter)" id="greetToPointcut"/> <aop:before method="preGreeting" pointcut-ref="greetToPointcut"/> </aop:aspect> </aop:config>
<aop:pointcut>如果位于<aop:aspect>元素中,则命名切点只能被当前<aop:aspect>内定义的元素访问到,为了能被整个<aop:config>元素中定义的所有增强访问,则必须在<aop:config>下定义切点,且必须保证<aop:pointcut>在<aop:aspect>之前定义:
<aop:config proxy-target-class="true"> <aop:pointcut expression="target(com.ivy.NaiveWaiter)" id="greetToPointcut"/> <aop:aspect ref="adviceMethods"> <aop:before method="preGreeting" pointcut-ref="greetToPointcut"/> </aop:aspect> <aop:aspect ref="adviceMethods"> <aop:after method="preGreeting" pointcut-ref="greetToPointcut"/> </aop:aspect> </aop:config>
各类增强配置
- 后置增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:after-returning method="afterReturning" pointcut="target(com.ivy.Seller)" returning="retVal"/> </aop:aspect> </aop:config>
增强对应方法:
public void afterReturning(int retVal) {
// 增强方法,retVal和配置文件中的returning属性值相同
}
如果增强不希望接收返回值,就把returning属性和增强方法的对应入参去掉即可。
2. 环绕增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:around method="aroundMethod" pointcut="execution(* serveTo(..) and within(com.ivy.Waiter))"/> </aop:aspect> </aop:config>
3. 抛出异常增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:after-throwing method="afterThrowingMethod" pointcut="target(com.ivy.Seller) and execution(* checkBill(..))" throwing="iae"/> </aop:aspect> </aop:config>
public void afterThrowingMethod(IllegalArgumentException iae) {
}
4. Final增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:after method="afterMethod" pointcut="execution(* com..*.Waiter.greetTo(..))"/> </aop:aspect> </aop:config>
5. 引介增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:declare-parents types-matching="com.ivy.Waiter+" implement-interface="com.ivy.Seller" default-impl="com.ivy.SmartSeller"/> </aop:aspect> </aop:config>
<aop:declare-parents>通过implement-interfaces属性声明要实现的接口,通过default-impl属性指定默认的接口实现,然后通过type-matching属性以切点表达式语法指定哪些bean需要引介Seller接口的实现。