Spring基础:AOP编程(2)

[size=x-large][b]基于ProxyFactory的AOP编程[/b][/size]

Spring只支持方法连接点,包括了5种类型的增强。
[list]
[*]前置增强
[*]后置增强
[*]环绕增强
[*]异常抛出增强
[*]引介增强
[/list]

1. 前置异常
这里使用一个服务员作为例子,服务员向顾客打招呼,并且提供服务。首先我们创建一个服务员的接口,然后再创建一个不那么友好的服务员,他直接走到顾客面前就开始提供服务了。我们应该给他们做功课,让他们更加有礼貌一些。

public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}


就是这个没什么经验的服务员类:

public class NaiveWaiter implements Waiter {
public void greetTo(String name) {
System.out.println("greet to " + name + "..");
}
public void serveTo(String name) {
System.out.println("serve to " + name + "..");
}
}


在这里我们给这个服务加上前置增强类,让这个服务员在见到顾客时先打招呼:

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object obj)
throws Throwable {
String clientName = (String) args[0];
System.out.println("How are you! Mr." + clientName + ".");
}
}


用Spring提供的ProxyFactory进行测试:

public class TestBeforeAdvice {
public static void main(String[] args) {
Waiter waiter = new NaiveWaiter();
BeforeAdvice advice = new GreetingBeforeAdvice();
ProxyFactory pf = new ProxyFactory();
// 设置目标类
pf.setTarget(waiter);
// 设置增强,这里可以添加多个增强
pf.addAdvice(advice);

Waiter proxy = (Waiter) pf.getProxy();
proxy.greetTo("John");
proxy.serveTo("John");
}
}


输出:
[color=blue]
How are you! Mr.John.
greet to John..
How are you! Mr.John.
serve to John..
[/color]

当然我们也可以采用Spring的方式来配置增强,需要用ProxyFactoryBean来代替上面的ProxyFactory

<bean id="greetingBefore" class="com.firethewhole.maventest07.advice.GreetingBeforeAdvice"/>
<bean id="target" class="com.firethewhole.maventest07.advice.NaiveWaiter"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
p:interceptorNames="greetingBefore"
p:proxyTargetClass="true"
p:target-ref="target"/>

target:代理的目标对象。
proxyInterfaces:代理所要实现的接口,可以有多个。
interfaces:是上面的属性的别名。
interceptorNames:需要织入目标对象的Bean列表。
singleton:返回的代理是否是单例,默认为单例。
optimize:为true时,使用CGLib代理,否则使用JDK代理。
proxyTargetClass:是否对类进行代理(而不是针对接口进行代理),设置为true时,使用CGLib代理。

让我们来测试一下:

String configPath = "com/firethewhole/maventest07/advice/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("John");

输出:
[color=bule]
How are you! Mr.John.
greet to John..
How are you! Mr.John.
serve to John..
[/color]

2. 后置增强:
在为顾客提供完服务之后,也应该有礼貌。

public class GreetingAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("Please enjoy yourself!");
}
}


<bean id="greetingAfter" class="com.firethewhole.maventest07.advice.GreetingAfterAdvice"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
p:interceptorNames="greetingAfter"
p:proxyTargetClass="true"
p:target-ref="target"/>

[color=blue]
greet to John..
Please enjoy yourself!
serve to John..
Please enjoy yourself!
[/color]

3. 环绕增强
Spring在这里直接使用了AOP联盟的接口org.aopalliance.intercept.MethodInterceptor

public class GreetingInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] args = invocation.getArguments();
String clientName = (String) args[0];
System.out.println("How are you! Mr." + clientName + ".");
Object obj = invocation.proceed();
System.out.println("Please enjoy yourself!");
return obj;
}
}


<bean id="greetingAround" class="com.firethewhole.maventest07.advice.GreetingInterceptor"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
p:interceptorNames="greetingAround"
p:proxyTargetClass="true"
p:target-ref="target"/>

输出:
[color=blue]
How are you! Mr.John.
greet to John..
Please enjoy yourself!
How are you! Mr.John.
serve to John..
Please enjoy yourself!
[/color]
我们看到方法执行的前后都被织入了增强。

4.异常抛出增强

public class ForumServiceThrowException {
public void removeForum(int forumId) {
throw new RuntimeException("运行异常。");
}
public void updateForum(int forumId) throws Exception {
throw new SQLException("数据更新操作异常");
}
}


public class TransactionManager implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable{
System.out.println("---------------");
System.out.println("method:" + method.getName());
System.out.println("抛出异常:" + ex.getMessage());
System.out.println("成功回滚事务。");
}
}


这里进行配置织入异常抛出增强

<bean id="transacionManager" class="com.firethewhole.maventest07.advice.TransactionManager"/>
<bean id="forumServiceTarget" class="com.firethewhole.maventest07.advice.ForumServiceThrowException"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transacionManager"
p:proxyTargetClass="true"
p:target-ref="forumServiceTarget"/>

[color=red]****我在采用上面的测试程序进行测试的时候,发现确实在抛出异常之后,走到了增强之中,但是在增强代码结束之后,最终异常还是会被抛出。[/color]

4. 引介增强
引介增强和上面的增强都不太一样,可以理解为在运行时为一个类对象添加了新的功能,这将极大地改变我们编写代码时的思路。

这里添加一个新的接口,为性能监视类添加是否需要监控的功能。

public interface Monitorable {
void setMonitorActivate(boolean active);
}


这里是增强类

public class ControllablePerformanceMonitor extends
DelegatingIntroductionInterceptor implements Monitorable {

private ThreadLocal<Boolean> monitorStatusMap = new ThreadLocal<Boolean>();

public void setMonitorActivate(boolean active) {
monitorStatusMap.set(active);
}

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object obj = null;
if (monitorStatusMap.get() != null && monitorStatusMap.get()) {
PerformanceMonitor.begin(mi.getClass().getName() + "."
+ mi.getMethod().getName());
obj = super.invoke(mi);
PerformanceMonitor.end();
} else {
obj = super.invoke(mi);
}
return obj;
}
}


配置文件:

<bean id="pmonitor" class="com.firethewhole.maventest07.introduce.ControllablePerformanceMonitor"/>
<bean id="forumServiceTarget" class="com.firethewhole.maventest07.introduce.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.firethewhole.maventest07.introduce.Monitorable"
p:target-ref="forumServiceTarget"
p:interceptorNames="pmonitor"
p:proxyTargetClass="true"/>


测试程序:

String configLocation = "com/firethewhole/maventest07/introduce/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
ForumService forumService = (ForumService) ctx.getBean("forumService");
forumService.removeForum(10);
forumService.removeTopic(1022);

Monitorable moniterable = (Monitorable) forumService;
moniterable.setMonitorActivate(true);
forumService.removeForum(20);
forumService.removeTopic(1022);


输出:
[color=blue]
模拟删除Forum记录:10
模拟删除Topic记录:1022
begin monitor...
模拟删除Forum记录:20
end monitor...
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeForum花费20毫秒。
begin monitor...
模拟删除Topic记录:1022
end monitor...
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeTopic花费20毫秒。
[/color]

可以看到在更改可检测属性为true之后,增强才变的有效的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值