【Spring】AOP - 面向切面

面向切面 - 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配置文件:

<?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:

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();
	}
}


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().");
	}
}

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().");
	}
}

执行结果:

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方法,如果忘记,通知将会阻止被通知的方法的调用。还可以在通知里多次调用被通知的方法。

示例:

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

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){
			
		}
	}
}

结果:

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作为参数。

示例:

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

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");
	}
}

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);
	}
}

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>元素:

示例:

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

package com.springtest;

public interface ExtendedInterface {
    void extendedExecute();
}

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会实现此接口。

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

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

示例:

<?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)。


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().");
	}
}

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


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()方法。

示例:

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){
			
		}
	}
}

执行结果:

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的切面声明没有太大区别。

示例:

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);
	}
}

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){
			
		}
	}
	*/
}

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"); 
	}
}

执行结果:

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:

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){
			
		}
	}
	*/
}

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(); 
	}
}

执行结果:

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所不能支持的许多类型的切点。




评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值