您的位置:首页 > 编程语言 > Java开发

spring中AOP3

2015-11-01 18:19 603 查看
4.6spring的AOP支持
之前讲到的都是AOP的advice都必须实现特定的接口,而配置上依赖于XML的繁琐配置。在spring2.0之后,对于AOP的实现与设置新增了两种方式:一种是基于XML schema的设置,另外一种是基于annotation的支持。两种方式对于AOP的实现都进行了简化。
Before使用xmlschema的方式:
#
package onlyfun.beforeadvice;

public
interface
IHello {
public
void
hello(String
msg);
}
#
package onlyfun.beforeadvice;
public class HelloSpeaker implementsIHello {
@Override
publicvoid hello(String msg) {
//TODO Auto-generated method stub
System.out.println(msg);
}

}
#
package onlyfun.beforeadvice;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.aspectj.lang.JoinPoint;
public
class
LogBeforeAdvice {
private Logger
logger = Logger.getLogger(this.getClass().getName());

public
void
before(JoinPoint joinPoint){
logger.log(Level.INFO,"method starts ..."+
joinPoint.getSignature().getDeclaringTypeName()+
"."+
joinPoint.getSignature().getName());

}
}

#
<?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"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean
id="helloSpeaker"
class ="onlyfun.beforeadvice.HelloSpeaker"
/>
<bean
id="logBeforeAdvice"class ="onlyfun.beforeadvice.LogBeforeAdvice"/>
<aop:config>
<aop:aspect
id="logging"
ref="logBeforeAdvice">
<aop:before

pointcut="execution(*onlyfun.beforeadvice.IHello.*(..))"
method = "before"/>
</aop:aspect>
</aop:config>

</beans>
#test
package onlyfun.beforeadvice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public
class
TestLogBefore {

public
static void
main(String[]
args) {
// TODO Auto-generated method stub
ApplicationContextcontext =
new ClassPathXmlApplicationContext("spring-config2.xml");
//这里和之前advice不太一样,原先获得的是代理的id,现在直接是
//被代理对象的id
IHellohello= (IHello)context.getBean("helloSpeaker");
hello.hello("this adudu ");
}

}
从该例子可以看出不再需要声明PRoxyFactoryBean,所有的AOP的配置实在<aop:config>标签中设置的;<aop:aspect>标签定义Aspect的实现,也就是advice的实例。
Xml配置中开头的红色部分需要注意,引入了AOP,且指定了spring的AOP的相关xsd解析的版本。

<aop:before>标签标示设置advice将作为before advice, pointcut属性定义Pointcut形式,execution(*
onlyfun.beforeadvice.IHello.*(..))
这三部分的颜色分别代表了返回值,方法名称,和输入参数值,*返回值任意,(..)参数为任意类型。
Method表示设置advice上要调用的方法,在这里设置调用LogBeforeAdvice的before方法。
如果需要重用pointcut可以这么写:

<aop:config>
<aop:pointcut
id="logHello"
expression="execution(*onlyfun.beforeadvice.IHello.*(..))"
/>
<aop:aspect
id="logging"
ref="logBeforeAdvice">
<aop:before

pointcut-ref="logHello"
method = "before"/>
</aop:aspect>
</aop:config>

这里的jar包需要考虑使用的是spring3.2.4的所有jar,还有commons-logging.jar,AspectJWeaver1.6.10.jar,还有aopalliance1.0.jar

4.6.2BeforeAdvice基于注解的形式
Spring2.0中可以基于Annotation来设置AOP的advice,在XML的设置上可以简化,IHello,HelloSpeaker,Test等和原来的相同,余下的是
#LogBeforeAdvice @annotation
package onlyfun.beforeadvice;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public
class
LogBeforeAdvice2 {
private Logger
logger = Logger.getLogger(this.getClass().getName());

@Before("execution(*onlyfun.beforeadvice.IHello.*(..))")
public
void
before(JoinPoint joinPoint){
logger.log(Level.INFO,"method starting ..."+joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
}
}
#spring-config3.xml
<?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"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean
id="helloSpeaker"
class ="onlyfun.beforeadvice.HelloSpeaker"
/>
<bean
id="logBeforeAdvice"class ="onlyfun.beforeadvice.LogBeforeAdvice2"/>

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
这里使用的是<aop:aspect-autoproxy/>,@Aspect

可以看出基于annotation的形式,几乎不用再xml里设置什么,只需要实例化Advice与我们的目标对象。

这里要将一个类设置为Aspect,只要使用@Aspect在类上表示它是Aspect的实现即可,@Before表示该方法在应用为BeforeAdvice
时调用,当中直接编写pointcut表达式。

这里实现接口的方式、xmlschema的方式、annotation的方式究竟哪种advice的实现方式好?

4.6.3pointcut的定义
Spring2.0中声明pointcut,主要包括表达式execution,签名signature。
Execution(modifiers-pattern?
Ret-type-pattern
Declaring-type-pattern?
Name-pattern(param-pattern)
Throws-pattern?)
存取修饰匹配,传回类型匹配,类类型匹配,方法名称匹配(参数类型匹配),异常类型匹配,有问号的地方可以省略不声明。

传回类型一般用*表示所有传回值类型都符合,也可以配置完整类型名称。方法名称匹配也可以使用*。参数类型匹配()表示没有参数,(type)表示带有一个类型为type的参数;(*)表示带有一个参数,且参数类型为任意;(..)表示零个或者多个参数。

Execution(public **(..))符合任何公开的方法
Execution(*hello*(..))符合hello开头的方法
Execution(* onlyfun.beforeadvice.IHello.*(..))IHello接口中声明的任何方法
Execution(*onlyfun.advice.service.*.*(..))该包下声明的所有方法
Execution(*onlyfun.advice.service..*.*(..))service包或者其子包下的所有的方法
Within(onlyfun.advice.service.*)符合该包下声明的任何方法
Within(onlyfun.advice.service..*)符合该报及其子包下的任何方法。
此外还有this、target、args等。

spring2.0中结合@pointcut的annotation定义方式,可以让pointcut在定义上更加容易,定义包括两部分:pointcut表达式和pointcut签名。如:
@Pointcut(“execution(*hello*(..))”)//pointcut表达式
Private void anyHello();//签名

如要使用所定义的Pointcut可以如下使用pointcut签名:
@Before(“anyHello()”)

这个例子相当于直接在@Before中定义一下的pointcut表示式
@Before(“execution(*hello*(..))”)

Pointcut的定义时可以使用&& || !
,它们用在相应的签名上.
@Pointcut(“anyHello()||anyWelcome()”)//@pointcut表达式
Private void anyHelloWelcome();//pointcut签名

如:例子
package onlyfun.beforeadvice;

import org.aspectj.lang.annotation.Pointcut;

public
class
CommonPointcut {
@Pointcut("execution(* hello*(..))")
public
void
anyHello();

@Pointcut("execution(* welcome*(..))")
public
void
anyWelcome();

@Pointcut("execution(*onlyfun.beforeadvice.IHello.*(..))")
public
void
hello();
@Pointcut("anyHello()||anyWelcome()")
public
void
anyHelloWelcome();
}

#
package onlyfun.beforeadvice;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public
class
LogBeforeAdvice2 {
private Logger
logger = Logger.getLogger(this.getClass().getName());

@Before("execution(*onlyfun.beforeadvice.IHello.*(..))")
public
void
before(JoinPoint joinPoint){
logger.log(Level.INFO,"method starting ..."+joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
}

@Before("onlyfun.beforeadvice.CommonPointcut.anyHelloWelcome()")
public
void
show(JoinPoint joinPoint){
logger.log(Level.INFO,"method show().......anyhellowelcome()");

}
}

在commonPointcut中定义的pointcut,使用时只需要指定完整类名称加上Pointcut的签名。如:@Before("onlyfun.beforeadvice.CommonPointcut.anyHelloWelcome()")
只要满足相应的pointcut,将会在拦击的时候先调用show方法,在执行pointcut中设置的被拦击的方法。配置文件不变。

ApplicationContextcontext =
new ClassPathXmlApplicationContext("spring-config3.xml");

IHellohello= (IHello)context.getBean("helloSpeaker");
hello.hello("this adudu ");
测试文件在执行上面的代码的时候,就会有两个pointcut,2个interceptor,
先调用before方法,在调用show方法。

也就是单独一个类中声明pointcut,按照表达式和签名声明pointcut,使用是可以再切入的方法上使用@Before(“该单独类的包路径和pointcut的签名方法()”)即可。

同时也可以在aop标签中指定pointcut
<aop:before pointcut =”onlyfun.pointcutadvice.CommonPointcut.anyHelloWelcome()”
Method=”before”/>

4.6.4 AfterReturningAdvice
基于XMLschema实现
相应的advice类不用实现任何类和接口,里面写的方法随便,
只要在配置文件中
<aop:config>
<aop:pointcut
id="logHello"
expression="execution(*onlyfun.afteradvice.IHello.*(..))"
/>
<aop:aspect
id="logging"
ref="logAfterAdvice">
<aop:before

pointcut-ref="logHello"
method = "after"/>
</aop:aspect>
</aop:config>

即可。
下面的例子是使用了注解annotation的,注意其中pointcut的使用和需要处理的方法服务:
package onlyfun.afteradvice;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public
class
AfterReturnningAdvice2 {
private Logger
logger = Logger.getLogger(this.getClass().getName());
//声明一个pointcut,包含表达式和签名两部分
@Pointcut("execution(* onlyfun.afteradvice.IHello.*(..))")
private
void
logging(){}

//直接使用注解,里面是pointcut的签名
@Before("logging()")
public
void
before(JoinPoint joinPoint){
logger.log(Level.INFO,"before method showing ......");
}
//该处是带有返回值的形式
@AfterReturning(pointcut="logging()",returning="retVal")
public
void
after(JoinPoint joinPoint,Object
retVal){
logger.log(Level.INFO,"after method showing ......");
}
}

这里是使用的<aop:aspect-autoproxy/>

此外对于aroundadvice和throwadvice,aroundadvice也是不需要继承和实现,只需要自己定义一个invoke方法,在proceed()执行前后加入要加入的东西即可。
@Around(“execution(*onlyfun.aroundadvice.IHello.*(..))”)
Public Objectinvoke(ProceedingJoinPoint joinPoint)throws Throwable{}

其他类似。Throwadvice,也是类似
@AfterThrowing(pointcut=”logging()”,throwing=”throwable”)
Public void afterThrowing(JoinPointjoinPoint,Throwable throwable){}

以上是注解形式,下面是xmlschema的形式
<aop:around …….>
<aop:after-throwing …>具体可以参考xmlschema的具体形式。



AOP总结一下:
主要是cross-cutting、cross-cuttingconcern 、aspect、advice、introduction、interceptor、pointcut、advisor、jointpoint这几个概念。
在业务之外的需要添加的服务如日志动作等,可以记为cross-cutting concern,若干个cross-cutting concern可以合成一个Aspects(如日志动作、事务处理、权限过滤等集合到一起,),每一个如日志动作称为一个advice(服务),而这样的服务需要在哪里加入,则需要pointcut,advisor给予明确的地点或者是时机。执行服务时可以从jointPoint中获得相应信息如getArgs(),getSignature(),getTarget等,供使用。而被代理对象的方法是根据pointcut中设置的表达式过滤的,同时由interceptor拦截器进行拦截,根据advice的方法前后等定义在方法执行前后执行相应的advice服务。Introduction则是可以给被代理的对象提供新的行为,而不用修改被代理对象的任何代码。
主要内容摘自《spring2.0技术手册》林信良著,其中代码自己编写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: