AOP联盟为增强定义了org.aopalliance.aop.Advice接口,Spring支持5种类型的增强:

    1)前置增强:org.springframework.aop.BeforeAdvice 代表前置增强,因为Spring 只支持方法级的增强,所有MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强,而BeforeAdvice是为了将来版本扩展需要而定义的;
    2)后置增强:org.springframework.aop.AfterReturningAdvice 代表后增强,表示在目标方法执行后实施增强;
    3)环绕增强:org.aopalliance.intercept.MethodInterceptor 代表环绕增强,表示在目标方法执行前后实施增强;
    4)异常抛出增强:org.springframework.aop.ThrowsAdvice 代表抛出异常增强,表示在目标方法抛出异常后实施增强;
    5)引介增强:org.springframework.aop.IntroductionInterceptor 代表引介增强,表示在目标类中添加一些新的方法和属性。
 
1、前置增强
    模拟服务员向顾客表示欢迎和对顾客提供服务。
Waiter接口:
package com.yyq.advice;
public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}

NaiveWaiter服务类:

package com.yyq.advice;
public class NaiveWaiter implements Waiter {
@Override
public void greetTo(String name) {
System.out.println("greet to " + name + "...");
}
@Override
public void serveTo(String name) {
System.out.println("serving to " + name + "...");
}
}

前置增强实现类:

package com.yyq.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
String clientName = (String) objects[0];
System.out.println("How are you ! Mr." + clientName + ".");
}
}

测试方法:

@Test
public void testBeforeAdvice(){
Waiter target = new NaiveWaiter();
BeforeAdvice advice = new GreetingBeforeAdvice();
ProxyFactory pf = new ProxyFactory(); //Spring提供的代理工厂
pf.setTarget(target); //设置代理目标
pf.addAdvice(advice);
Waiter proxy = (Waiter)pf.getProxy(); //生成代理实例
proxy.greetTo("John");
proxy.serveTo("Tom");
}
输出结果:
How are you ! Mr.John.
greet to John...
How are you ! Mr.Tom.
serving to Tom...
 
在Spring中配置:beans.xml

<bean id="greetingAdvice" class="com.yyq.advice.GreetingBeforeAdvice"/>
<bean id="target" class="com.yyq.advice.NaiveWaiter"/> <bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingAdvice"
p:target-ref="target"/>

  ProxyFactoryBean 是FactoryBean接口的实现类。

    · target:代理的目标对象;
    · proxyInterfaces:代理所实现的接口,可以是多个接口。该属性还有一个别名属性interfaces;
    · interceptorNames:需要织入目标对象的Bean列表,采用Bean的名称指定。这些Bean必须是实现了org.aopalliance.intercept.Method 或 org.springframework.aop.Advisor的Bean,配置中的顺序对应调用的顺序;
    · singleton:返回的代理是否是单实例,默认为单实例;
    · optimize:当设置为true时,强制使用CGLib代理。对于singleton的代理,我们推荐使用CGLib,对于其他作用域类型的代理,最好使用JDK代理。原因是CGLib创建代理时速度慢,而创建出的代理对象运行效率较高,而使用JDK代理的表现正好相反;
    · proxyTargetClass:是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。
测试方法:

@Test
public void testBeforeAdvice2(){
String configPath = "com\\yyq\\advice\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter1");
waiter.greetTo("Joe");
}
输出结果:
How are you ! Mr.Joe.
greet to Joe...
 
2、后置增强
    后置增强在目标类方法调用后执行。模拟服务员在每次服务后使用礼貌用语。
GreetingAfterAdvice后置增强实现类:

package com.yyq.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class GreetingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o2) throws Throwable {
System.out.println("Please enjoy yourself.");
}
}

在beans.xml文件添加后置增强:

<bean id="greetingBefore" class="com.yyq.advice.GreetingBeforeAdvice"/>
<bean id="greetingAfter" class="com.yyq.advice.GreetingAfterAdvice"/>
<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingBefore,greetingAfter"
p:target-ref="target"/>

测试方法:

 @Test
public void testBeforeAndAfterAdvice(){
String configPath = "com\\yyq\\advice\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter2");
waiter.greetTo("Joe");
}
结果输出:
How are you ! Mr.Joe.
greet to Joe...
Please enjoy yourself.
 
3、环绕增强
    环绕增强允许在目标类方法调用前后织入横切逻辑,它综合实现了前置、后置增强两者的功能。
GreetingInterceptor环绕增强实现类:

package com.yyq.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class GreetingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object[] args = methodInvocation.getArguments();
String clientName = (String) args[0];
System.out.println("Hi,Mr " + clientName + ".");
Object obj = methodInvocation.proceed();
System.out.println("Please enjoy yourself~");
return obj;
}
}

  Spring 直接使用AOP联盟所定义的MethodInterceptor作为环绕增强的接口。该接口拥有唯一的接口方法 Object invoke(MethodInvocation invocation), MethodInvocation不但封装目标方法及其入参数组,还封装了目标方法所在的实例对象,通过MethodInvocation的getArguments()可以获取目标方法的入参数组,通过proceed()反射调用目标实例相应的方法。

在beans.xml文件添加环绕增强:

 <bean id="greetingAround" class="com.yyq.advice.GreetingInterceptor"/>
<bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.yyq.advice.Waiter"
p:interceptorNames="greetingAround"
p:target-ref="target"/>

测试方法:

  @Test
public void testAroundAdvice(){
String configPath = "com\\yyq\\advice\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter)ctx.getBean("waiter3");
waiter.greetTo("Joe");
}
结果输出:
Hi,Mr Joe.
greet to Joe...
Please enjoy yourself~
 
4、异常抛出增强
    异常抛出增强最适合的应用场景是事务管理,当参与事务的某个Dao发送异常时,事务管理器就必须回滚事务。
Forum业务类:

package com.yyq.advice;
public class Forum {
private int forumId;
public int getForumId() {
return forumId;
}
public void setForumId(int forumId) {
this.forumId = forumId;
}
}

ForumService业务类:

package com.yyq.advice;
import java.sql.SQLException;
public class ForumService {
public void removeForum(int forumId){
System.out.println("removeForum....");
throw new RuntimeException("运行异常");
}
public void updateForum(Forum forum)throws Exception{
System.out.println("updateForum");
throw new SQLException("数据更新操作异常。");
}
}

TransactionManager异常抛出增强实现类:

package com.yyq.advice;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
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("成功回滚事务。");
}
}
    ThrowAdvice异常抛出增强接口没有定义任何方法,它是一个标识接口,在运行期Spring使用反射的机制自行判断,我们采用以下签名形式定义异常抛出的增强方法:void afterThrowing(Mehod method, Object[] args, Object target, Throwable);方法名必须为afterThrowing,方法入参规定,前三个参数是可选的,要么三个入参提供,要么不提供,最后一个入参是Throwable或者子类。
在beans.xml文件添加异常抛出增强:

<bean id="transactionManager" class="com.yyq.advice.TransactionManager"/>
<bean id="forumServiceTarget" class="com.yyq.advice.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="transactionManager"
p:target-ref="forumServiceTarget"
p:proxyTargetClass="true"/>

测试方法:

@Test
public void testThrowsAdvice(){
String configPath = "com\\yyq\\advice\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
ForumService fs = (ForumService)ctx.getBean("forumService");
try{
fs.removeForum(10);
} catch (Exception e) {}
try{
fs.updateForum(new Forum());
} catch (Exception e) {}
}
结果输出:
----------------
method:removeForum
抛出异常:运行异常
成功回滚事务。
updateForum
----------------
method:updateForum
抛出异常:数据更新操作异常。
成功回滚事务。
 
5、引介增强
        引介增强为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的。通过引介增强,我们可以为目标类添加一个接口的实现,即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现某个接口的代理。Spring定义了引介增强接口IntroductionInterceptor,该接口没有定义任何的方法,Spring为该接口提供了DelegatingIntroductionInterceptor实现类。
Monitorable:用于标识目标类是否支持性能监视的接口

package com.yyq.advice;
public interface Monitorable {
void setMonitorActive(boolean active);
}

ControllablePerformanceMonitor 为引介增强实现类:

package com.yyq.advice;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {
private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();
@Override
public void setMonitorActive(boolean active) {
MonitorStatusMap.set(active);
}
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;
}
}

PerformanceMonitor监视类:

package com.yyq.advice;

public class PerformanceMonitor {
private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
public static void begin(String method) {
System.out.println("begin monitor...");
MethodPerformance mp = new MethodPerformance(method);
performanceRecord.set(mp);
}
public static void end(){
System.out.println("end monitor...");
MethodPerformance mp = performanceRecord.get();
mp.printPerformance();
}
}

MethodPerformance记录性能信息:

public class MethodPerformance {
private long begin;
private long end;
private String serviceMethod;
public MethodPerformance(String serviceMethod){
this.serviceMethod = serviceMethod;
this.begin = System.currentTimeMillis();
}
public void printPerformance(){
end = System.currentTimeMillis();
long elapse = end - begin;
System.out.println(serviceMethod + "花费" + elapse + "毫秒。");
}
}

在beans.xml文件添加引介增强:

<bean id="pmonitor" class="com.yyq.advice.ControllablePerformanceMonitor"/>
<bean id="forumServiceImplTarget" class="com.yyq.advice.ForumServiceImpl"/>
<bean id="forumService2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.yyq.advice.Monitorable"
p:interceptorNames="pmonitor"
p:target-ref="forumServiceImplTarget"
p:proxyTargetClass="true"/>
测试方法:

@Test
public void testIntroduce(){
String configPath = "com\\yyq\\advice\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
ForumServiceImpl forumServiceImpl = (ForumServiceImpl)ctx.getBean("forumService2");
forumServiceImpl.removeForum(23);
forumServiceImpl.removeTopic(1023);
Monitorable monitorable = (Monitorable)forumServiceImpl;
monitorable.setMonitorActive(true);
forumServiceImpl.removeForum(22);
forumServiceImpl.removeTopic(1023);
}
结果输出:
模拟删除Forum记录:23
模拟删除Topic记录:1023
begin monitor...
模拟删除Forum记录:22
end monitor...
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeForum花费40毫秒。
begin monitor...
模拟删除Topic记录:1023
end monitor...
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeTopic花费21毫秒。
 
 

Spring AOP 创建增强类的更多相关文章

  1. (spring-第17回【AOP基础篇】) 创建增强类

    一.   增强类包含的信息: a)   横切逻辑(插入的具体代码) b)   部分连接点信息(在方法的哪个位置插入代码,比如方法前.方法后等). 二.   增强的类型 每一种增强有一个需要实现的增强类 ...

  2. Spring aop:decare-parent 为类增加新的方法

    Spring aop:decare-parent 为类增加新的方法: 使用XML配置的方式: XML: <?xml version="1.0" encoding=" ...

  3. Spring AOP切面变成——创建增强类

    说明 Spring使用增强类定义横向逻辑,同时Spring只支持方法连接点,增量类还包含在方法的哪一点添加横切代码的方位信息.所以增强既包含横向逻辑,又包含部分连接点的信息. 类型 按着增强在目标类方 ...

  4. Spring aop——前置增强和后置增强 使用注解Aspect和非侵入式配置

    AspectJ是一个面向切面的框架,它扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入,所以它有一个专门的编译器用来生成遵守字节码字节编码规范的Class文件 确保使用jdk为5.0以 ...

  5. 阿里四面:你知道Spring AOP创建Proxy的过程吗?

    Spring在程序运行期,就能帮助我们把切面中的代码织入Bean的方法内,让开发者能无感知地在容器对象方法前后随心添加相应处理逻辑,所以AOP其实就是个代理模式. 但凡是代理,由于代码不可直接阅读,也 ...

  6. spring aop无法拦截类内部的方法调用

    1.概念 拦截器的实现原理就是动态代理,实现AOP机制.Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的:二是基于 CGLIB 技术而实现的.如果目标对象实现 ...

  7. Spring AOP 创建切面

        增强被织入到目标类的所有方法中,但是如果需要有选择性的织入到目标类某些特定的方法中时,就需要使用切点进行目标连接点的定位.增强提供了连接点方位信息:如织入到方法前面.后面等,而切点进一步描述织 ...

  8. Spring AOP(基于代理类的AOP实现)

    #基于代理类的AOP实现:step1: 1 package com.sjl.factorybean; /**切面类*/ import org.aopalliance.intercept.MethodI ...

  9. Spring AOP创建Throwdvice实例

    1.异常发生的时候,通知某个服务对象做处理 2.实现throwsAdvice接口 接口实现: public interface IHello { public void sayHello(String ...

随机推荐

  1. 如何不通过系统升级来安装window10正式版?(特别针对Xp用户)

    今天是个特殊的日子7/29,相信大家都等了很久了吧,win10正式版终于上线,一些不懂电脑的人只会通过360和腾讯管家等来升级到win10(XP用户除外),而对于大多数像我这样对系统比较热衷的人,我相 ...

  2. Java_Swing实现小球沿正弦曲线运动的代码

    1 package zuidaimapack_1; import java.awt.*; import javax.swing.*; /** *Java_Swing实现小球沿正弦曲线运动的代码 * @ ...

  3. 【First Missing Positive】cpp

    题目: Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2 ...

  4. union与union all的区别

    首先说下union与join的区别 1.union是以行增加的方式,进行连接:join是以列增加的方式进行连接: 2.union连接查询的两个表的字段必须要一一对应,数目相等:join则没有要求,但是 ...

  5. 处理XML的几种方式

    晚上突然收到codeproject发来的订阅邮件,上面是关于用DOM出来XML,想总结一下有哪些方式可以轻松得处理XML DOM:这个再古老不过了,貌似大学开XML课程的时候,老师首推DOM XPat ...

  6. 使用HTML5中postMessage实现Ajax中的POST跨域问题

    HTML5中提供了在网页文档之间相互接收与发送信息的功能.使用这个功能,只要获取到网页所在窗口对象的实例,不仅仅同源(域+端口号)的web网页之间可以互相通信,甚至可以实现跨域通信. 浏览器支持程度: ...

  7. apple开发者账号申请

    1.  登陆appleID. 2. 进入 Your Account 3. 在Account Summary 中的MemberShips中选择第一个(界面大概如下) 4.选择后进入下图. 5. yes ...

  8. C51关键字

    C51 中的关键字 关键字 用途 说明 auto 存储种类说明 用以说明局部变量,缺省值为此 break 程序语句 退出最内层循环 case 程序语句 Switch语句中的选择项 char 数据类型说 ...

  9. Ubuntu下配置Docbook环境

    1.准备环境 $sudo apt-get install xsltproc $sudo apt-get install docbook-xsl $sudo apt-get install docboo ...

  10. Base64编解码Android和ios的例子,补充JNI中的例子

    1.在Android中java层提供了工具类:android.util.Base64; 里面都是静态方法,方便直接使用: 使用方法如下: // Base64 编码: byte [] encode =  ...