循序渐进之Spring AOP(3) - 配置代理

上一篇介绍了几种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),在下一篇中单独介绍


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页