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

【Spring】AOP - 面向切面

2018-01-12 18:45 246 查看


面向切面 - AOP

切面实现了横切关注点(跨越多个应用对象的逻辑)的模块化:




术语


通知(Advice)

在AOP术语中,切面的工作被成为通知。通知定义了切面是什么以及何时使用。

Spring切面可以应用5中类型的通知:

Before —— 在方法被调用之前调用通知;
After —— 在方法完成之后调用通知,无论方法执行是否成功;
After-returning —— 在方法成功执行之后调用通知;
After-throwing —— 在方法抛出异常后调用通知;
Around —— 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为;


连接点(Joinpoint)

连接点是在应用执行过程中能够插入切面的一个点。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。


切点(Pointcut)

切点的定义会匹配通知所要织入的一个或多个连接点。通常使用明确的类和方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。

切点用于准确定位应该在什么地方应用切面的通知


切面(Aspect)

切面是通知和切点的结合。通知和切点共同定义了关于切面的全部内容——它是什么,在何时和何处完成其他功能。


引入(Introduction)

引入允许我们向现有的类添加新方法或属性,通过通知类,从而可以在无需修改现有的类的情况下,让它们具有新的行为和状态。

参见<aop:declare-parents>元素的使用,引入新的接口行为。


织入(Weaving)

织入是将切面应用到目标对象来创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中(注入前置、后置通知等)。

在目标对象的生命周期里有多个点可以进行织入:

编译期—— 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ;
类加载期—— 切面在目标类家在到JVM时被织入,这种方式需要特殊的类加载器(ClassLoader);
运行期—— 切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面的;


Spring对AOP的支持

Spring提供了4中各具特色的AOP支持:

基于代理的经典AOP;
@AspectJ注解驱动的切面;
纯POJO切面;
注入式AspectJ切面;

Spring通知是Java编写 —— Spring所创建的通知都是用标准的Java类编写的;

Spring在运行期通知对象 —— Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入Spring AOP的切面;

Spring只支持方法连接点 —— Spring基于动态代理,所以Spring只支持方法连接点,不支持构造器和字段连接点;


SpringAOP 之 定义切点

Spring AOP中,需要使用AspectJ的切点表达式语言来定义切点。


Spring AOP支持的AspectJ切点指示符

Spring仅支持AspectJ切点指示器的一个子集:

AspectJ指示器描述
execution用于匹配方法执行的连接点
within用于匹配指定类型内的方法执行
this用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配
target用于匹配当前目标对象类型的执行方法,注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配
args用于匹配当前执行的方法传入的参数为指定类型的执行方法
@within用于匹配持有指定注解类型内的方法
@target用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解
@args用于匹配当前执行的方法传入的参数持有指定注解的执行
@annotation用于匹配当前执行方法持有指定注解的方法
beanSpring AOP扩展的,用于匹配特定名称的Bean对象的执行方法
reference pointcut表示引用其他命名切入点
在Spring中尝试使用其他AspectJ指示器时,将会抛出IllegalArgumentException异常。
http://sishuok.com/forum/posts/list/281.html


SpringAOP 之 基于POJO切面


在XML中声明切面

Spring提供了声明式切面的选择。

Spring的AOP配置元素简化了基于POJO切面的声明:

AOP配置元素功能
<aop:advisor>定义一个AOP通知器
<aop:after>定义一个AOP后置通知(不考虑被通知的方法是否执行成功)
<aop:after-returning>定义一个AOP返回后通知
<aop:after-throwing>定义一个AOP抛出后通知
<aop:around>定义一个AOP环绕通知
<aop:aspect>定义一个切面
<aop:before>定义一个AOP前置通知
<aop:config>顶层的AOP元素。大多数<aop:*>元素必须包含在<aop:config>里
<aop:pointcut>定义一个切点
<aop:declare-parents>为被通知的对象引入额外的接口,并透明地实现


声明前置和后置通知

XML Bean配置文件:

[html] view
plain copy

<?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:p="http://www.springframework.org/schema/p"

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

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

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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="advised" class="com.springtest.AdvisedObj" />

<bean id="advising" class="com.springtest.AdvisingObj" />

<aop:config>

<aop:aspect ref="advising">

<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(..))" />

<aop:before pointcut-ref="performance" method="beforeExecute" />

<aop:after pointcut-ref="performance" method="afterExecute" />

</aop:aspect>

</aop:config>

</beans>

Java Code:

[html] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AdvisedObj;

import com.springtest.AdvisingObj;

public class SpringCoreTest{

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/... .../beans_config.xml");

AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");

advisedObj.perform();

}

}

[html] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AdvisedObj {

private static final Logger logger = LoggerFactory.getLogger(AdvisedObj.class);

public void perform(){

logger.info("AdvisedObj perform().");

}

}

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);

public void beforeExecute(){

logger.info("AdvisingObj beforeExcecute().");

}

public void afterExecute(){

logger.info("AdvisingObj afterExecute().");

}

}

执行结果:

[java] view
plain copy

00:52:24.350 [main] INFO com.springtest.AdvisingObj - AdvisingObj beforeExcecute().

00:52:24.367 [main] INFO com.springtest.AdvisedObj - AdvisedObj perform().

00:52:24.367 [main] INFO com.springtest.AdvisingObj - AdvisingObj afterExecute().

关于Spring AOP配置元素,大多数的AOP配置元素必须在<aop:config>元素的上下文内使用。

在所有的通知元素中,pointcut属性定义了通知所应用的切点。pointcut属性的值是使用AspectJ切点表达式语法所定义的切点

<aop:pointcut>元素所定义的切点可以被同一个<aop:aspect>元素内的所有通知元素所引用。如果想让定义的切点能够在多个切面使用,可以把<aop:pointcut>元素放在<aop:config>元素的作用域内。


声明环绕通知

使用<aop:round>元素。使用环绕通知,可以完成之前前置通知和后置通知所实现的相同功能,但是只需要在一个方法中实现。

参考下面新的通知方法,它使用了ProceedingJoinPoint作为方法的参数。这个对象能让我们在通知里调用被通知方法。通知方法可以完成任何它所需要做的事情,如果希望把控制转给被通知的方法时,可以调用ProceedingJoinPoint的proceed方法。

必须调用proceed方法,如果忘记,通知将会阻止被通知的方法的调用。还可以在通知里多次调用被通知的方法。

示例:

[java] view
plain copy

<?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:p="http://www.springframework.org/schema/p"

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

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

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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="advised" class="com.springtest.AdvisedObj" />

<bean id="advising" class="com.springtest.AdvisingObj" />

<aop:config>

<aop:aspect ref="advising">

<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(..))" />

<!--

<aop:before pointcut-ref="performance" method="beforeExecute" />

<aop:after pointcut-ref="performance" method="afterExecute" />

-->

<aop:around pointcut-ref="performance" method="roundExecute" />

</aop:aspect>

</aop:config>

</beans>

[java] view
plain copy

package com.springtest;

import org.aspectj.lang.ProceedingJoinPoint;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);

public void beforeExecute(){

logger.info("AdvisingObj beforeExcecute().");

}

public void afterExecute(){

logger.info("AdvisingObj afterExecute().");

}

public void roundExecute(ProceedingJoinPoint joinpoint){

try{

logger.info("AdvisingObj before roundExecute().");

joinpoint.proceed();

logger.info("AdvisingObj after roundExecute().");

}catch(Throwable t){

}

}

}

结果:

[java] view
plain copy

01:36:00.808 [main] INFO com.springtest.AdvisingObj - AdvisingObj before roundExecute().

01:36:00.825 [main] INFO com.springtest.AdvisedObj - AdvisedObj perform().

01:36:00.825 [main] INFO com.springtest.AdvisingObj - AdvisingObj after roundExecute().


为通知传递参数

有时候通知并不仅仅是对方法进行简单包装,还需要校验传递给方法的参数值,这时候为通知传递参数就非常有用了。

通过配置实现将被通知方法的参数传递给通知,如下指定String参数,然后在args参数中标识了将parameter作为参数。

示例:

[java] view
plain copy

<?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:p="http://www.springframework.org/schema/p"

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

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

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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="advised" class="com.springtest.AdvisedObj" />

<bean id="advising" class="com.springtest.AdvisingObj" />

<aop:config>

<aop:aspect ref="advising">

<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(String)) and args(parameter)" />

<!--

<aop:before pointcut-ref="performance" method="beforeExecute" />

<aop:after pointcut-ref="performance" method="afterExecute" />

<aop:around pointcut-ref="performance" method="roundExecute" />

-->

<aop:before pointcut-ref="performance" method="parameterExecute" arg-names="parameter" />

</aop:aspect>

</aop:config>

</beans>

[java] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AdvisedObj;

import com.springtest.AdvisingObj;

public class SpringCoreTest{

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/... .../beans_config.xml");

AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");

advisedObj.perform("TestParameter");

}

}

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AdvisedObj {

private static final Logger logger = LoggerFactory.getLogger(AdvisedObj.class);

public void perform(String parameter){

logger.info("AdvisedObj perform(), parameter is {}.", parameter);

}

}

[java] view
plain copy

package com.springtest;

import org.aspectj.lang.ProceedingJoinPoint;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);

public void beforeExecute(){

logger.info("AdvisingObj beforeExcecute().");

}

public void afterExecute(){

logger.info("AdvisingObj afterExecute().");

}

public void roundExecute(ProceedingJoinPoint joinpoint){

try{

logger.info("AdvisingObj before roundExecute().");

joinpoint.proceed();

logger.info("AdvisingObj after roundExecute().");

}catch(Throwable t){

}

}

public void parameterExecute(String parameter){

logger.info("AdvisingObj parameterExecute(), parameter is {}.",parameter);

}

}


通过切面引入新的功能

利用被称为引入的AOP概念,切面也可以为Spring Bean添加新方法。

利用<aop:declare-parents>元素:

示例:

添加一个新的接口及实现类:

[java] view
plain copy

package com.springtest;

public interface ExtendedInterface {

void extendedExecute();

}

[java] view
plain copy

package com.springtest;

import com.springtest.ExtendedInterface;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class ExtendedObj implements ExtendedInterface{

private static final Logger logger = LoggerFactory.getLogger(ExtendedObj.class);

public void extendedExecute(){

logger.info("ExtendedObj extendedExecute().");

}

}

在AOP配置中,<aop:declare-parents>声明了此切面锁通知的Bean在它的对象结构中拥有新的父类型,那些Bean会实现此接口。

[java] view
plain copy

<?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:p="http://www.springframework.org/schema/p"

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

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

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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="advised" class="com.springtest.AdvisedObj" />

<bean id="advising" class="com.springtest.AdvisingObj" />

<bean id="extended" class="com.springtest.ExtendedObj" />

<aop:config>

<aop:aspect ref="advising">

<!--

<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(String)) and args(parameter)" />

<aop:before pointcut-ref="performance" method="beforeExecute" />

<aop:after pointcut-ref="performance" method="afterExecute" />

<aop:around pointcut-ref="performance" method="roundExecute" />

<aop:before pointcut-ref="performance" method="parameterExecute" arg-names="parameter" />

-->

<aop:declare-parents

types-matching="com.springtest.AdvisedObj+"

implement-interface="com.springtest.ExtendedInterface"

delegate-ref="extended" />

</aop:aspect>

</aop:config>

</beans>

[java] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AdvisedObj;

import com.springtest.AdvisingObj;

import com.springtest.ExtendedInterface;;

public class SpringCoreTest{

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/beans_config.xml");

//AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");

//advisedObj.perform("TestParameter");

ExtendedInterface advisedObj = (ExtendedInterface)ctx.getBean("advised");

advisedObj.extendedExecute();

}

}


SpringAOP 之 @AspectJ注解切面

使用注解来创建切面是AspectJ5所引入的关键特性。AspectJ面向注解的模型可以非常简单地通过少量注解把任意类转换为切面(不需要使用Java语言扩展)。这种新特性通常称为@AspectJ

示例:

[java] view
plain copy

<?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:p="http://www.springframework.org/schema/p"

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

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

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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy />

<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="advised" class="com.springtest.AspectJAnnotationAdvisedObj" />

<bean id="advising" class="com.springtest.AspectJAnnotationAdvisingObj" />

</beans>

<aop:aspectj-autoproxy />将在Spring上下文中创建一个AnnotationAwareAspectJAutoProxyCreator类,它会自动代理一些Bean,这些Bean的方法需要与使用@Aspect注解的Bean所定义的切点相匹配,因此,被代理的目标对象类和使用@Aspect注解的类都应该定义成Bean,否则无法找到它们(定义Bean:advised和advising)。

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AspectJAnnotationAdvisedObj{

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisedObj.class);

public void perform(){

logger.info("AspectJAnnotationAdvisedObj perform().");

}

}

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterThrowing;

@Aspect

public class AspectJAnnotationAdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);

@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(..))")

public void performance() {

}

@Before("performance()")

public void beforeExecute(){

logger.info("AspectJAnnotationAdvisingObj beforeExcecute().");

}

@AfterReturning("performance()")

public void afterExecute(){

logger.info("AspectJAnnotationAdvisingObj afterExecute().");

}

}

@Pointcut注解用于定义一个可以在@AspectJ切面内可重用的切点。@Pointcut注解的值是一个AspectJ切点表达式,这里表示该切点必须匹配perform方法。切点的名称来源于注解所应用的方法名称。因此,该切点的民称为performance()。performance()方法的实际内容并不重要,在这里它事实上是空的,其实该方法本身只是一个标识,供@Pointcut注解依附。

@Before注解标识是前置通知方法,@AfterReturning注解标识是后置通知方法。

performance()切点的名称作为参数的值赋给了所有的通知注解,以这种方式来标识每一个通知方法应该应用在哪里。

[java] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AspectJAnnotationAdvisedObj;

import com.springtest.AspectJAnnotationAdvisingObj;

public class AspectJAnnotationTest {

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");

AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");

advisedObj.perform();

}

}

<aop:aspectj-autoproxy>仅仅使用@AspectJ注解作为指引来创建基于代理的切面,但本质上它仍然是一个Spring风格的切面。


注解环绕通知

使用@Around注解可以创建环绕通知;被环绕通知的方法必须接受一个ProceedingJoinPoint对象作为方法入参,并在对象上调用proceed()方法。

示例:

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

@Aspect

public class AspectJAnnotationAdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);

@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(..))")

public void performance() {

}

/*

@Before("performance()")

public void beforeExecute(){

logger.info("AspectJAnnotationAdvisingObj beforeExcecute().");

}

@AfterReturning("performance()")

public void afterExecute(){

logger.info("AspectJAnnotationAdvisingObj afterExecute().");

}

*/

@Around("performance()")

public void roundExecute(ProceedingJoinPoint joinpoint){

try{

logger.info("AspectJAnnotationAdvisingObj before roundExecute().");

joinpoint.proceed();

logger.info("AspectJAnnotationAdvisingObj after roundExecute().");

}catch(Throwable t){

}

}

}

执行结果:

[java] view
plain copy

02:44:04.540 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj before roundExecute().

02:44:04.562 [main] INFO c.s.AspectJAnnotationAdvisedObj - AspectJAnnotationAdvisedObj perform().

02:44:04.562 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj after roundExecute().


传递参数给所标注的通知

使用@AspectJ注解为通知传递参数,与Spring基于XML的切面声明没有太大区别。

示例:

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class AspectJAnnotationAdvisedObj{

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisedObj.class);

public void perform(String parameter){

logger.info("AspectJAnnotationAdvisedObj perform(), parameter is {}.", parameter);

}

}

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

@Aspect

public class AspectJAnnotationAdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);

@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(String)) && args(parameter)")

public void performance(String parameter) {

}

@Before("performance(parameter)")

public void beforeExecute(String parameter){

logger.info("AspectJAnnotationAdvisingObj beforeExcecute(), parameter is {}.", parameter);

}

@AfterReturning("performance(parameter)")

public void afterExecute(String parameter){

logger.info("AspectJAnnotationAdvisingObj afterExecute(), parameter is {}.", parameter);

}

/*

@Around("performance()")

public void roundExecute(ProceedingJoinPoint joinpoint){

try{

logger.info("AspectJAnnotationAdvisingObj before roundExecute().");

joinpoint.proceed();

logger.info("AspectJAnnotationAdvisingObj after roundExecute().");

}catch(Throwable t){

}

}

*/

}

[java] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AspectJAnnotationAdvisedObj;

import com.springtest.AspectJAnnotationAdvisingObj;

public class AspectJAnnotationTest {

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");

AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");

advisedObj.perform("Parameter1");

}

}

执行结果:

[java] view
plain copy

03:03:19.837 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj beforeExcecute(), parameter is Parameter1.

03:03:19.856 [main] INFO c.s.AspectJAnnotationAdvisedObj - AspectJAnnotationAdvisedObj perform(), parameter is Parameter1.

03:03:19.856 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj afterExecute(), parameter is Parameter1.


标注引入

使用基于注解的AOP为已有的Bean引入接口。等价于<aop:declare-parents>的注解是@AspectJ的@DeclareParents。

示例:使用上一节的ExtendInterface和ExtendedObj:

[java] view
plain copy

package com.springtest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.DeclareParents;

@Aspect

public class AspectJAnnotationAdvisingObj {

private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);

@DeclareParents(

value="com.springtest.AspectJAnnotationAdvisedObj+",

defaultImpl=ExtendedObj.class)

public static ExtendedInterface extended;

/*

@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(String)) && args(parameter)")

public void performance(String parameter) {

}

@Before("performance(parameter)")

public void beforeExecute(String parameter){

logger.info("AspectJAnnotationAdvisingObj beforeExcecute(), parameter is {}.", parameter);

}

@AfterReturning("performance(parameter)")

public void afterExecute(String parameter){

logger.info("AspectJAnnotationAdvisingObj afterExecute(), parameter is {}.", parameter);

}

@Around("performance()")

public void roundExecute(ProceedingJoinPoint joinpoint){

try{

logger.info("AspectJAnnotationAdvisingObj before roundExecute().");

joinpoint.proceed();

logger.info("AspectJAnnotationAdvisingObj after roundExecute().");

}catch(Throwable t){

}

}

*/

}

[java] view
plain copy

package com.springtest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.springtest.AspectJAnnotationAdvisedObj;

import com.springtest.AspectJAnnotationAdvisingObj;

import com.springtest.ExtendedInterface;;

public class AspectJAnnotationTest {

public static void main(String[] args){

ApplicationContext ctx =

new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");

/*

AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");

advisedObj.perform("Parameter1");

*/

ExtendedInterface advisedObj = (ExtendedInterface)ctx.getBean("advised");

advisedObj.extendedExecute();

}

}

执行结果:

[java] view
plain copy

03:16:30.784 [main] INFO com.springtest.ExtendedObj - ExtendedObj extendedExecute().

@DeclareParents注解由3部分组成:

value属性等同于<aop:delcare-parents>的types-matching属性。它标识应该被引入指定接口的Bean类型。
defaultImpl属性等同于<aop:declare-parents>的default-impl属性。它标识该类提供了所引入接口的实现。
由@DeclaeParents注解所标注的static属性指定了将被引入的接口。

(该注解类AspectJAnnotationAdvisingObj需要声明为Spring应用上下文中的一个Bean。)


SpringAOP 之 注入AspectJ切面

AspectJ提供了Spring AOP所不能支持的许多类型的切点。

转载自:http://blog.csdn.net/robinjwong/article/details/25568481
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring AOP 切面