上一篇介绍了几种Advice(增强),并通过代码演示了生成代理的方式,下面来看通过配置文件配置方式把Advice织入目标类。
注意,配置文件方式仍然不是Spring AOP的最好方式,学习配置方式也是为了循序渐进的掌握内核技术。
接口SmartCar
public interface SmartCar { void lock(String userName); }
实现类MyCar
public class MyCar implements SmartCar { @Override public void lock(String userName) { System.out.println(userName + "锁车"); } }
定义了两个增强,一个在锁车方法前执行,提示检查窗户是否关闭,一个在锁车方法后执行,"哔哔"声提示锁车成功
public class BeforeAdviceDemo implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object obj) throws Throwable { System.out.println("请检查窗户是否关好"); } }
public class AfterAdviceDemo implements AfterReturningAdvice { @Override public void afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable { System.out.println("哔哔"); } }
applicationContext.xml: 用配置文件来声明代理
<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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="beforeAdvice" class="demo.aop.BeforeAdviceDemo" /> <bean id="afterAdvice" class="demo.aop.AfterAdviceDemo" /> <bean id="target" class="demo.aop.MyCar" /> <bean id="myCar" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="target" p:proxyTargetClass="true"> <property name="interceptorNames"> <list> <idref local="beforeAdvice" /> <idref local="afterAdvice" /> </list> </property> </bean> </beans>
测试代码
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("demo/aop/applicationContext.xml"); SmartCar myCar = (SmartCar)context.getBean("myCar"); myCar.lock("Tom"); }执行结果
请检查窗户是否关好 Tom锁车 哔哔
配置文件中首先声明了3个bean,分别是增强的目标类和两个增强,没有特别的配置内容。重点是ProxyFactoryBean的配置,来看看它可配置的属性和用法。
target | 目标对象,ref另一个bean |
proxyTargetClass | 是否对类进行代理(而不是对接口),true或false,设置为true时,使用CGLib代理技术 |
interceptorNames | 织入目标对象的Advice(实现了Advisor或者MethodInterceptor接口的bean) |
proxyInterfaces | 代理所要实现的接口,如果指定了proxyTargetClass=true,此属性会被忽略 |
optimize | 设置为true时,强制使用CGLib代理技术 |
下面再分别增加一个环绕增强和一个异常抛出增强。
先修改MyCar类,使它能够抛出异常,粗心的约翰会忘记锁车而抛出一个异常
public class MyCar implements SmartCar { @Override public void lock(String userName) { if(userName.equals("Careless John")) { throw new RuntimeException(userName + "忘记锁车"); } else { System.out.println(userName + "锁车"); } } }环绕增强类
public class AroundAdviceDemo implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object[] args = invocation.getArguments(); String name = (String)args[0]; System.out.print("Hey, " + name); Object obj = invocation.proceed(); //调用目标方法 System.out.println("Goodbye! " + name); return obj; } }异常抛出增强
public class ThrowsAdviceDemo implements ThrowsAdvice { public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { System.out.println("捕获异常:" + ex.getMessage()); System.out.println("(报警)滴滴滴滴滴滴滴滴滴滴滴滴"); } }applicationContext.xml
<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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="beforeAdvice" class="demo.aop.BeforeAdviceDemo" /> <bean id="afterAdvice" class="demo.aop.AfterAdviceDemo" /> <bean id="aroundAdvice" class="demo.aop.AroundAdviceDemo" /> <bean id="throwsAdvice" class="demo.aop.ThrowsAdviceDemo" /> <bean id="target" class="demo.aop.MyCar" /> <bean id="myCar" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="target" p:proxyTargetClass="true"> <property name="interceptorNames"> <list> <idref local="aroundAdvice" /> <idref local="throwsAdvice" /> <idref local="beforeAdvice" /> <idref local="afterAdvice" /> </list> </property> </bean> </beans>测试代码
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("demo/aop/applicationContext.xml"); SmartCar myCar = (SmartCar)context.getBean("myCar"); myCar.lock("Tom"); System.out.println("-------------------------"); myCar.lock("Careless John"); }运行结果
Hey, Tom请检查窗户是否关好 Tom锁车 哔哔 Goodbye! Tom ------------------------- Hey, Careless John请检查窗户是否关好 捕获异常:Careless John忘记锁车 (报警)滴滴滴滴滴滴滴滴滴滴滴滴
除了上面的四种增强,还有一种特殊的引介增强(Introduction),在下一篇中单独介绍