Spring -- aop, 用Aspectj进行AOP开发

1. 概要

添加类库:aspectjrt.jaraspectjweaver.jar
添加aop schema.
定义xml元素:<aop:aspectj-autoproxy>
编写java,并用@Aspect注解成通知

     AspectJ 支持 5 种类型的通知注解:

  @Before: 前置通知,在方法执行之前执行

  @After: 后置通知,在方法执行之后执行

  @AfterRunning: 返回通知,在方法返回结果之后执行

  @AfterThrowing: 异常通知,在方法抛出异常之后

  @Around: 环绕通知,围绕着方法执行

配置成普通bean元素即可.
 

前置通知:@Before

@Aspect

public class AudienceAdvice {

  @Before("execution(* WelcomeService.*(..))")

  public void takeSeats(){..}

   @Before("execution(* WelcomeService.*(..))")

  public void turnOffCellphone(JoinPoint jp){..}

JoinPoint参数可访问连接点细节,入方法名和参数等.

jp.getTarget()//目标对象

jp.getThis()//当前的代理对象

jp.getArgs();//方法调用参数

jp.getSignature().getName()//方法签名

后置通知:@After

    @After("execution(* *..WelcomeService.*(..))")

    public void applaud(){..}

后置通知在目标方法执行完成之后执行.一个切面aspect包含很多通知.

@After

    后置通知表明目标方法执行完之后,不论是否抛异常,都会织入该通知.

@AfterReturning

    方法返回后通知只在目标方法返回以后执行,若抛异常不执行.

@AfterReturning(pointcut="",returning="res")

public void xxx(Joinput jp,Object res)

在后置通知中可接收到返回值.res即是用来接收返回值的对象.

环绕通知:@Around

    @Around("execution(* *..WelcomeService.*(..))")

    public void around(ProceedingPointCut jp){..}

注意:可以控制目标方法是否调用,以及返回完全不同的对象,要慎用.

指定优先级:

@Aspect

@Order(0)

public class xxx{...}

加上@Order注解可以指定加入切面的优先级(先后顺序,值越小,优先级越高)

引入通知:

@Aspect

public class MyAspectjIntroduction {

  @DeclareParents(value="*..*Service*",

                   defaultImpl=ModifyDateImpl.class)

  private ModifyDate md ;

}

value:指定哪些类可以应用该属性

defaultImpl:指定接口的实现类

典型Aspectj切入点表达式定义:

execution(* cn.itcast.WelcomeServiceImpl.*(..))

execution(public * *..WelcomeServiceImpl.*(..))

execution(public void *..WelcomeServiceImpl.*(..))

execution(public void *..*Service.*(double,double))..

切入点表达式运算(&& || !)

@Pointcut("execution(..) || execution(..)")

 

2. 示例代码:

Performer.java 演员接口

public interface Performer {
	public void show();
}

Singer.java 接口实现

public class Singer implements Performer {
	public void show() {
		System.out.println("其实我是个演员!");
//		String str = null ;
//		str.toString();
	}
}

Audience.java 观众类, 即通知类

package cn.itcast.spring.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 观众, 需要添加 @Aspect
 */
@Aspect
public class Audience {
	
	/**
	 * 引入通知,
	 */
	@DeclareParents(value="cn.itcast.spring.aop.aspectj.Singer",defaultImpl=ModifyDateImpl.class)
	private ModifyDate md ;
	/**
	 * 定义在切入点, 切入点表达式
	 */
	//任意返回值  Performer中 任意方法 任意参数 
	@Pointcut("execution(* cn.itcast.spring.aop.aspectj.Performer.*(..))")
	public void perform(){
	}
	/**
	 * 坐好
	 */
	@Before(value="perform()")
	public void takeSeat(){
		System.out.println("takeSeat");
	}
	
	/**
	 * 关机
	 */
	@Before(value="perform()")
	public void turnOffCellphone(JoinPoint jp){
		System.out.println(jp.getSignature().getName());
		System.out.println(jp.getArgs());
		System.out.println(jp.getTarget());
		System.out.println(jp.getThis());
		System.out.println("turnOffCellphone");
	}
	
	/**
	 * returning:指定哪个参数接受方法的返回值
	 */
	@AfterReturning(pointcut="perform()",returning="ret")
	public void applaud(Object ret){
		System.out.println("applaud");
		System.out.println("ret = " + ret);
	}
	
	/**
	 * 退票
	 * throwing:指定哪个参数接受异常信息
	 */
	@AfterThrowing(pointcut="perform()",throwing="e")
	public void demandMoney(Exception e){
		System.out.println("demandMoney");
		System.out.println("出事了 " + e.getMessage());
	}
	
	@After("perform()")
	public void goHome(){
		System.out.println("goHome");
	}
	
	/*
	* 环绕通知
	*/
	@Around(value="perform()")
	public Object watch(ProceedingJoinPoint pjp){
		try {
			System.out.println("takeSeat");
			System.out.println("turnOffCellphone");
			Object o = pjp.proceed();
			System.out.println("applaud");
			return o;
		} catch (Throwable e) {
			System.out.println("demandMoney");
		}
		finally{
			System.out.println("goHome");
		}
		return null ;
	}
}

ModifyDate.java 引入通知接口

/**
 * 修改日期
 */
public interface ModifyDate {
	public void setModifyDate(Date date);
	public Date getModifyDate();
}

ModifyDateImpl.java 引入通知实现

public class ModifyDateImpl implements ModifyDate {
	private Date date ;
	public Date getModifyDate() {
		return date;
	}

	public void setModifyDate(Date date) {
		this.date = date ;
	}
}

aspectj.xml 配置文件

<?xml version="1.0"?>
<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
    <!-- 观众通知 -->
    <bean id="audience" class="cn.itcast.spring.aop.aspectj.Audience" />
    
    <!-- 歌手 -->
    <bean id="singer" class="cn.itcast.spring.aop.aspectj.Singer" />
    
    <!-- 使用aspectj自动产生代理 -->
    <aop:aspectj-autoproxy />
</beans>

App.java 测试代码

public class App {
	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext(
				"cn/itcast/spring/aop/aspectj/aspectj.xml");
		Performer p = (Performer) ac.getBean("singer");
		p.show();
		//测试引入通知
		((ModifyDate)p).setModifyDate(new Date());
		System.out.println(((ModifyDate)p).getModifyDate());
	}
}


3. 使用pojo+xml开发aop

基于注解的aspectj声明优先于xml配置.基于xml的配置是spring专有的.aspectj得到越来越多的支持,具备更好的重用性.

其他bean 和 通知类 都不会改变, 只会不再需要用注解, 改用xml文件

pojo.xml 引入通知, 前置 后置 异常通知

<?xml version="1.0"?>
<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
    <!-- 观众 -->
    <bean id="audience" class="cn.itcast.spring.aop.pojo.Audience" />
    <!-- 歌手 -->
    <bean id="singer" class="cn.itcast.spring.aop.pojo.Singer" />
    
    <!-- aop配置 -->
    <aop:config>
        <aop:aspect ref="audience">
            <!-- 引入通知 -->
            <aop:declare-parents types-matching="cn.itcast.spring.aop.pojo.Singer"
                                 implement-interface="cn.itcast.spring.aop.pojo.ModifyDate"
                                 default-impl="cn.itcast.spring.aop.pojo.ModifyDateImpl"/>
            <!-- 单独定义切入点表达式 -->
            <aop:pointcut id="audiencePointcut" expression="execution(* cn.itcast.spring.aop.pojo.Performer.*(..))"/>
            
            <!-- 前置通知 -->
            <aop:before method="takeSeat" pointcut-ref="audiencePointcut" />
            <aop:before method="turnOffCellphone" pointcut-ref="audiencePointcut"/>
            
            <!-- 后置通知,ret指定哪个参数接受返回值 -->
            <aop:after-returning method="applaud" pointcut-ref="audiencePointcut" returning="ret"/>
            
            <!-- throwing:指定哪个参数接受异常信息 -->
            <aop:after-throwing method="demandMoney" pointcut-ref="audiencePointcut" throwing="ex"/>
            
            <!--  -->
            <aop:after method="goHome" pointcut-ref="audiencePointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

pojoAround.xml 环绕通知

<?xml version="1.0"?>
<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
    <!-- 观众 -->
    <bean id="audience" class="cn.itcast.spring.aop.pojo.AudienceAround" />
    <!-- 歌手 -->
    <bean id="singer" class="cn.itcast.spring.aop.pojo.Singer" />
    
    <!-- aop配置 -->
    <aop:config>
        <aop:aspect ref="audience">
            <aop:around method="watch" pointcut="execution(* cn.itcast.spring.aop.pojo.Performer.*(..))"/>
        </aop:aspect>
    </aop:config>
</beans>



 





 

 

posted @ 2014-03-06 10:49  今晚打酱油_  阅读(238)  评论(0编辑  收藏  举报